在需要数据访问权限的独立Java应用程序中使用JDBC连接池时,大多数开发人员将使用commons-dbcp或c3p0 。 在本教程中,我们将讨论在独立Java应用程序中的Apache Tomcat Web容器中使用JDBC连接池。
- 支持高度并发的环境和多核/ CPU系统
- Commons-dbcp是单线程的,速度很慢
- Commons-dbcp很复杂(超过60个类),而tomcat-jdbc核心仅包含8个类
- 支持异步连接检索
- XA连接支持
- 连接池对象公开了可以注册用于监视目的的MBean
- 支持common-dbcp中的大多数属性,以及许多增强的属性
- 支持JDBC拦截器
- 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
依存关系
清单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>
领域对象模型
清单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;
}
}
数据库架构
在本教程中,我们将使用H2内存数据库。 有3个表:
- 联系人:该表存储联系人信息
- HOBBY:该表存储可用于该应用程序的兴趣爱好列表
- CONTACT_HOBBY_DETAIL:对Contact和Hobby类之间的多对多关系进行建模
清单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存储库抽象
清单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实施类
清单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类
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_,
结论
下载完整的Eclipse Maven Project 。
参考:来自我们的W4G合作伙伴 Clarence Ho的 独立Java应用程序中的Tomcat JDBC连接池使用 。
Clarence Ho是APress的Pro Spring 3的主要作者。 借助Pro Spring 3 ,您将学习Spring的基础知识和核心主题,并获得作者关于远程处理, Hibernate和EJB的见解和实际经验。 除了基础知识之外,您还将学习如何利用Spring框架构建企业Java应用程序的各个层或部分,例如事务,Web和表示层,部署等。 完整的示例应用程序使您可以应用本书中介绍的许多技术,并了解它们如何协同工作。
APress已为Java Code Geeks的读者提供了优惠券代码。 优惠券代码为: SPR76 ,有效期至2012年7月6日 。 该代码仅可从apress.com获得40%的电子书折扣 。
翻译自: https://www.javacodegeeks.com/2012/06/using-tomcat-jdbc-connection-pool-in.html
本文介绍了如何在独立的Java应用程序中使用Tomcat JDBC连接池代替传统的commons-dbcp和c3p0,以提高并发性能和系统支持。详细讲解了配置步骤、Spring整合、JPA实现以及测试案例,展示了如何利用Tomcat JDBC连接池的优势,如异步连接检索和XA连接支持。

1万+

被折叠的 条评论
为什么被折叠?



