在独立Java应用程序中使用Tomcat JDBC连接池

本文介绍了如何在独立的Java应用程序中使用Tomcat JDBC连接池代替传统的commons-dbcp和c3p0,以提高并发性能和系统支持。详细讲解了配置步骤、Spring整合、JPA实现以及测试案例,展示了如何利用Tomcat JDBC连接池的优势,如异步连接检索和XA连接支持。
这是从我们的客人文章W4G伙伴克拉伦斯豪的作者临春3从A按。 您可能会在文章结尾找到本书的折扣券代码,仅适用于Java Code Geeks的读者! 请享用!

在需要数据访问权限的独立Java应用程序中使用JDBC连接池时,大多数开发人员将使用commons-dbcpc3p0 。 在本教程中,我们将讨论在独立Java应用程序中的Apache Tomcat Web容器中使用JDBC连接池。

Tomcat 7的新功能之一是tomcat-jdbc连接池,它替代了commons-dbcp连接池。 下面列出了tomcat-jdbc相对于commons-dbcp和其他连接池库的主要优点:
  • 支持高度并发的环境和多核/ CPU系统
  • Commons-dbcp是单线程的,速度很慢
  • Commons-dbcp很复杂(超过60个类),而tomcat-jdbc核心仅包含8个类
  • 支持异步连接检索
  • XA连接支持
  • 连接池对象公开了可以注册用于监视目的的MBean
  • 支持common-dbcp中的大多数属性,以及许多增强的属性
  • 支持JDBC拦截器
有关配置的详细说明和文档,请参考Apache Tomcat网站上的官方文档页面。
在本教程中,我们将演示如何使用tomcat-jdbc开发简单的独立数据访问Java应用程序。 该应用程序将使用以下框架和库:
  • Spring Framework 3.1.1
  • 休眠4.1.3
  • Spring Data JPA 1.1.0
  • Tomcat JDBC连接池7.0.27
  • H2数据库1.3.167
  • 番石榴12.0
该示例是使用SpringSource Tool Suite开发的,可以在本文末尾下载压缩的存档 。 另一方面,本教程假定您已经对使用Spring和Hibernate开发JPA应用程序有所了解。

依存关系

项目依赖项由Maven管理。 以下是项目的POM文件(pom.xml)的片段。

清单1 –项目依赖性

<properties>
    <maven.test.failure.ignore>true</maven.test.failure.ignore>
    <spring.framework.version>3.1.1.RELEASE</spring.framework.version>
  <hibernate.version>4.1.3.Final</hibernate.version>
  <spring.data.jpa.version>1.1.0.RELEASE</spring.data.jpa.version>
  <tomcat.dbcp.version>7.0.27</tomcat.dbcp.version>
  <h2.version>1.3.167</h2.version>
  <slf4j.version>1.6.4</slf4j.version>
  <log4j.version>1.2.16</log4j.version>
  <guava.version>12.0</guava.version>
</properties>

<dependencies>

 <!-- Hibernate -->

  <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>       
      <version>${hibernate.version}</version>
  </dependency>

 <!-- Spring Framework -->

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${spring.framework.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.framework.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${spring.framework.version}</version>
  </dependency>

 <!-- Spring Data JPA -->

  <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>${spring.data.jpa.version}</version>
  </dependency>

 <!-- Tomcat DBCP -->

  <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-jdbc</artifactId>
      <version>${tomcat.dbcp.version}</version>
  </dependency>
          
 <!-- Logging -->

  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j.version}</version>
  </dependency>

  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${slf4j.version}</version>
      <scope>runtime</scope>
  </dependency>

  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${slf4j.version}</version>
      <scope>runtime</scope>
  </dependency>

  <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
  </dependency>
       
 <!-- Others -->

  <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>${h2.version}</version>
  </dependency>

  <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>${guava.version}</version>
  </dependency>
</dependencies>

领域对象模型

对象模型是一个简单的联系信息模型。 每个联系人都有其名字,姓氏和出生日期。 同样,每个联系人将与零个或多个爱好(例如游泳,慢跑,阅读等)相关联。 在DOM中,有两个主要类,即Contact和Hobby类。 清单2和3分别显示了这些类的代码清单。

清单2 – Contact类

@Entity
@Table(name = "contact")
public class Contact {

 private Long id;
 private int version;
 private String firstName;
 private String lastName;
 private Date birthDate;
 private Set<Hobby> hobbies = new HashSet<Hobby>();
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name = "ID")
 public Long getId() {
  return id;
 }
 
 public void setId(Long id) {
  this.id = id;
 }
 
 @Version
 @Column(name = "VERSION")
 public int getVersion() {
  return version;
 }
 
 public void setVersion(int version) {
  this.version = version;
 }
 
 @Column(name = "FIRST_NAME")
 public String getFirstName() {
  return firstName;
 }
 
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 @Column(name = "LAST_NAME")
 public String getLastName() {
  return lastName;
 }
 
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 
 @Column(name = "BIRTH_DATE")
 @Temporal(TemporalType.DATE)
 public Date getBirthDate() {
  return birthDate;
 }
 
 public void setBirthDate(Date birthDate) {
  this.birthDate = birthDate;
 } 
 
 @ManyToMany
 @JoinTable(name = "contact_hobby_detail", 
       joinColumns = @JoinColumn(name = "CONTACT_ID"), 
       inverseJoinColumns = @JoinColumn(name = "HOBBY_ID"))
 public Set<hobby> getHobbies() {
  return this.hobbies;
 }

 public void setHobbies(Set<hobby> hobbies) {
  this.hobbies = hobbies;
 }   
    
 public String toString() {  
  return "Contact - Id: " + id + ", First name: " + firstName 
    + ", Last name: " + lastName + ", Birthday: " + birthDate;
 }  
 
}

清单3 – Hobby类

@Entity
@Table(name = "hobby")
public class Hobby {

 private String hobbyId;
 private Set<Contact> contacts = new HashSet<Contact>();

 public Hobby() {
 }

 public Hobby(String hobbyId) {
  this.hobbyId = hobbyId;
 }

 public Hobby(String hobbyId, Set<Contact> contacts) {
  this.hobbyId = hobbyId;
  this.contacts = contacts;
 }

 @Id
 @Column(name = "HOBBY_ID")
 public String getHobbyId() {
  return this.hobbyId;
 }

 public void setHobbyId(String hobbyId) {
  this.hobbyId = hobbyId;
 }

 @ManyToMany
 @JoinTable(name = "contact_hobby_detail", 
       joinColumns = @JoinColumn(name = "HOBBY_ID"), 
       inverseJoinColumns = @JoinColumn(name = "CONTACT_ID"))
 public Set<Contact> getContacts() {
  return this.contacts;
 }

 public void setContacts(Set<Contact> contacts) {
  this.contacts = contacts;
 } 
 
}
在清单2和3中,注意到Contact和Hobby类之间存在多对多关系。

数据库架构

在本教程中,我们将使用H2内存数据库。 有3个表:

  • 联系人:该表存储联系人信息
  • HOBBY:该表存储可用于该应用程序的兴趣爱好列表
  • CONTACT_HOBBY_DETAIL:对Contact和Hobby类之间的多对多关系进行建模
清单4和5分别显示了数据库模式创建脚本和测试数据填充脚本的内容。

清单4 –数据库模式创建脚本(schema.sql)

DROP TABLE IF EXISTS CONTACT;

CREATE TABLE CONTACT (
 ID INT NOT NULL AUTO_INCREMENT
 ,FIRST_NAME VARCHAR(60) NOT NULL
 ,LAST_NAME VARCHAR(40) NOT NULL
 ,BIRTH_DATE DATE
 ,VERSION INT NOT NULL DEFAULT 0
 ,UNIQUE UQ_CONTACT_1 (FIRST_NAME, LAST_NAME)
 ,PRIMARY KEY (ID)
);

CREATE TABLE HOBBY (
  HOBBY_ID VARCHAR(20) NOT NULL
 ,PRIMARY KEY (HOBBY_ID)
);


CREATE TABLE CONTACT_HOBBY_DETAIL (
  CONTACT_ID INT NOT NULL
 ,HOBBY_ID VARCHAR(20) NOT NULL
 ,PRIMARY KEY (CONTACT_ID, HOBBY_ID)
 ,CONSTRAINT FK_CONTACT_HOBBY_DETAIL_1 FOREIGN KEY (CONTACT_ID)
  REFERENCES CONTACT (ID) ON DELETE CASCADE
 ,CONSTRAINT FK_CONTACT_HOBBY_DETAIL_2 FOREIGN KEY (HOBBY_ID)
  REFERENCES HOBBY (HOBBY_ID)
);

清单5 –测试数据填充脚本(test-data.sql)

insert into contact (first_name, last_name, birth_date) values ('Clarence', 'Ho', '1980-07-30');
insert into contact (first_name, last_name, birth_date) values ('Scott', 'Tiger', '1990-11-02');

insert into hobby (hobby_id) values ('Swimming');
insert into hobby (hobby_id) values ('Jogging');
insert into hobby (hobby_id) values ('Programming');
insert into hobby (hobby_id) values ('Movies');
insert into hobby (hobby_id) values ('Reading');

insert into contact_hobby_detail(contact_id, hobby_id) values (1, 'Swimming');
insert into contact_hobby_detail(contact_id, hobby_id) values (1, 'Movies'); 
insert into contact_hobby_detail(contact_id, hobby_id) values (2, 'Swimming');

服务层

在服务层中,存在2个接口:

  • ContactService:提供用于访问联系信息的服务
  • HobbyService:提供用于访问爱好信息的服务

清单6和7分别显示了ContactService和HobbyService接口。

清单6 – ContactService接口

public interface ContactService {

 public List<Contact> findAll();
 
 public Contact findById(Long id);
 
 public Contact save(Contact contact);
 
}

清单7 – HobbyService接口

public interface HobbyService {

 public List<Hobby> findAll();
 
}

弹簧配置

让我们看一下Spring配置。 清单8显示了数据源,事务和JPA配置。

清单8 – Spring JPA配置(datasource-tx-jpa.xml)

<!--Tomcat JDBC connection pool configutation -->
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
   <property name="driverClassName" value="org.h2.Driver" />
   <property name="url" value="jdbc:h2:mem:testdb" />
   <property name="username" value="sa" />
   <property name="password" value="" />
</bean>

<!--Intialize the database schema with test data -->
<jdbc:initialize-database data-source="dataSource">
   <jdbc:script location="classpath:schema.sql"/>
   <jdbc:script location="classpath:test-data.sql"/>
</jdbc:initialize-database>
  
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
   <property name="entityManagerFactory" ref="emf"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
   </property>
   <property name="packagesToScan" value="com.skywidesoft.tomcat.dbcp.tutorial.domain"/>
   <property name="jpaProperties">
    <props>
     <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
     <prop key="hibernate.max_fetch_depth">3</prop>
     <prop key="hibernate.jdbc.fetch_size">50</prop>
     <prop key="hibernate.jdbc.batch_size">10</prop>
     <prop key="hibernate.show_sql">true</prop>
    </props>
   </property>
</bean> 

<context:annotation-config/>

<!--Spring Data JPA Repository Configuration -->
<jpa:repositories base-package="com.skywidesoft.tomcat.dbcp.tutorial.repository"
         entity-manager-factory-ref="emf"
         transaction-manager-ref="transactionManager"/>

下面列出了清单8中配置的一些要点:

  • 对于dataSource bean,使用org.apache.tomcat.jdbc.pool.DataSource类为基础连接提供JDBC DataSource接口。 您将看到配置与使用commons-dbcp基本上相同。
  • <jdbc:initialize-database>标记是Spring 3.1对使用数据库架构和测试数据初始化数据库的支持
  • <jpa:repositories>标记用于配置Spring Data JPA的存储库抽象。

清单9显示了Spring应用程序上下文配置。

清单9 – Spring应用程序上下文(app-context.xml)

<import resource="classpath:datasource-tx-jpa.xml"/>

        <context:component-scan base-package="com.skywidesoft.tomcat.dbcp.tutorial.service.jpa"/>

Spring Data JPA存储库抽象

Spring Data JPA的存储库抽象为开发基于JPA的数据访问应用程序提供了一种简化的方法。 有关详细信息,请访问项目网站 。 存储库抽象层是使用Java界面开发的。 清单10和11分别显示了ContactRepository和HobbyRepository接口的代码清单。

清单10 – ContactRepository接口

public interface ContactRepository extends CrudRepository<Contact, Long>{

}

清单11 – HobbyRepository接口

public interface HobbyRepository extends CrudRepository<Hobby, String>{

}

请注意,该接口只是扩展了Spring Data Common的CrudRepository <T,ID>接口,该接口已经提供了常见的数据访问操作(例如findAll,findOne,保存,删除等)。

JPA实施类

下一步是开发清单6和7中的服务层接口的JPA实现。这些类采用Spring Framework的注解用于Spring bean声明,依赖项的自动装配和事务需求等。清单12和13显示了ContactServiceImpl和HobbyServiceImpl类。

清单12 – ContactServiceImpl类

@Service("contactService")
@Repository
@Transactional
public class ContactServiceImpl implements ContactService {

 final static Logger logger = LoggerFactory.getLogger(ContactServiceImpl.class);
 
 @Autowired
 private ContactRepository contactRepository;
 
 @Transactional(readOnly=true)
 public List<Contact> findAll() {
  logger.info("Finding all contacts");
  return Lists.newArrayList(contactRepository.findAll());
 }

 @Transactional(readOnly=true)
 public Contact findById(Long id) {
  return contactRepository.findOne(id);
 }

 public Contact save(Contact contact) {
  return contactRepository.save(contact);
 }

}

清单13 – HobbyServiceImpl类

@Service("hobbyService")
@Repository
@Transactional
public class HobbyServiceImpl implements HobbyService {

 @Autowired
 private HobbyRepository hobbyRepository;

 @Transactional(readOnly=true)
 public List<Hobby> findAll() {
  return Lists.newArrayList(hobbyRepository.findAll());
 }

}

测试中

让我们看看实际的应用程序。 清单14显示了ContactServiceTest类,该类仅从app-context.xml文件中引导Spring应用程序上下文,查找contactService bean,并调用findAll操作以从数据库中检索所有联系人。

清单14 – ContactServiceTest类

public class ContactServiceTest {

 public static void main(String[] args) {

  GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
  ctx.load("classpath:app-context.xml");
  ctx.refresh();
  
  ContactService contactService = ctx.getBean("contactService", ContactService.class);
  
  List<Contact> contacts = contactService.findAll(); 
  
  for (Contact contact: contacts) {
   System.out.println(contact);
  }  

 }

}
运行上面的类将在控制台输出窗口中产生以下输出(省略了其他不相关的输出):

2012-05-25 13:35:43,552 INFO [com.skywidesoft.tomcat.dbcp.tutorial.service.jpa.ContactServiceImpl] -
<Finding all contacts>
contact0_.BIRTH_DATE as BIRTH2_0_, contact0_.FIRST_NAME as FIRST3_0_,

从上面的输出中,您可以看到从数据库中正确检索了由test-data.sql脚本填充的联系信息。

结论

本教程介绍了如何在独立的Java应用程序中使用Tomcat的JDBC连接池。 Tomcat的JDBC连接池替代了commons-dbcp连接池,提供了更快,功能更丰富的JDBC连接池解决方案。 它的简洁设计,高性能,对高度并发环境的支持以及多核/ cpu系统使其成为Tomcat Web容器和独立Java应用程序环境中的JDBC连接池提供程序的极具吸引力的选择。

下载完整的Eclipse Maven Project

参考:来自我们的W4G合作伙伴 Clarence Ho的 独立Java应用程序中的Tomcat JDBC连接池使用

Clarence Ho是APress的Pro Spring 3的主要作者。 借助Pro Spring 3 ,您将学习Spring的基础知识和核心主题,并获得作者关于远程处理, HibernateEJB的见解和实际经验。 除了基础知识之外,您还将学习如何利用Spring框架构建企业Java应用程序的各个层或部分,例如事务,Web和表示层,部署等。 完整的示例应用程序使您可以应用本书中介绍的许多技术,并了解它们如何协同工作。

APress已为Java Code Geeks的读者提供了优惠券代码。 优惠券代码为: SPR76 ,有效期至20127月6日 。 该代码仅可从apress.com获得40%的电子书折扣


翻译自: https://www.javacodegeeks.com/2012/06/using-tomcat-jdbc-connection-pool-in.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值