- 浏览: 41612 次
- 性别:
- 来自: 北京
文章分类
最新评论
JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还
无法保证数据操作的原子性(要么全部生效,要么全部无效),如:
---------------------------------↓-------------------------------↓-----------------------------------
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");
---------------------------------↑-------------------------------↑-----------------------------------
由于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库
中”erica”对应的记录已经被更新,如果第二个操作失败,我们无法使得整个事务回滚到最
初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致
致命错误。
为了实现数据操作的原子性,我们需要在程序中引入事务逻辑,在JdbcTemplate中引入
事务机制,在Spring中有两种方式:
1. 代码控制的事务管理
2. 参数化配置的事务管理
下面就这两种方式进行介绍。
★ 代码控制的事务管理
首先,进行以下配置,假设配置文件为(Application-Context.xml):
---------------------------------↓-------------------------------↓-----------------------------------
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
---------------------------------↑-------------------------------↑-----------------------------------
配置中包含了三个节点:
● dataSource
这里我们采用了apache dhcp组件提供的DataSource实现,并为其配置了
JDBC驱动、数据库URL、用户名和密码等参数。
● transactionManager
针对JDBC DataSource类型的数据源,我们选用了
DataSourceTransactionManager
作为事务管理组件。
如果需要使用基于容器的数据源(JNDI),我们可以采用如下配置:
---------------------------------↓-------------------------------↓-----------------------------------
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
---------------------------------↑-------------------------------↑-----------------------------------
userDAO 申明了一个UserDAO Bean,并为其指定了dataSource和
transactionManger资源。
UserDAO对应的代码如下:
---------------------------------↓-------------------------------↓-----------------------------------
public class UserDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =
new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}
---------------------------------↑-------------------------------↑-----------------------------------
可以看到,在insertUser方法中,我们引入了一个新的模板类:
org.springframework.transaction.support.TransactionTemplate。
TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成
功后的事务提交。和JdbcTemplate一样,它使得我们无需在琐碎的try/catch/finally代码
中徘徊。在doInTransaction中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,
则将被自动提交。
这里我们故意制造了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自
增ID字段故意触发一个异常):
编写一个简单的TestCase来观察实际效果:
---------------------------------↓-------------------------------↓-----------------------------------
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
---------------------------------↑-------------------------------↑-----------------------------------
相信大家多少觉得上面的代码有点凌乱,Callback类的编写似乎也有悖于日常的编程
习惯(虽然笔者觉得这一方法比较有趣,因为它巧妙的解决了笔者在早期自行开发数据访问
模板中曾经遇到的问题)。
如何进一步避免上面这些问题?Spring 的容器事务管理机制在这里即体现出其强大
的能量。
★ 参数化配置的事务管理
在上面的Application-Context.xml增加一个事务代理(UserDAOProxy)配置,同时,
由于事务由容器管理,UserDAO不再需要TransactionManager设定,将其移除:
---------------------------------↓-------------------------------↓-----------------------------------
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
---------------------------------↑-------------------------------↑-----------------------------------
上面的配置中,UserDAOProxy节点配置了一个针对userDAO bean的事务代理(由
target属性指定)。
通过transactionAttributes属性,我们指定了事务的管理策略,即对所有以insert
开头的方法进行事务管理,如果被管理方法抛出异常,则自动回滚方法中的事务,如果成功
执行,则在方法完成之后进行事务提交。另一方面,对于其他方法(通过通配符*表示),
则进行只读事务管理,以获得更好的性能。
与之对应,UserDAO.insertUser的代码修改如下:
---------------------------------↓-------------------------------↓-----------------------------------
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
---------------------------------↑-------------------------------↑-----------------------------------
测试代码修改如下:
---------------------------------↓-------------------------------↓-----------------------------------
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意这里须通过代理Bean"userDAOProxy"获得引用,而不是直接getBean(“userDAO”)
//此外这里还存在一个有关强制转型的潜在问题,请参见Hibernate in Spring一节后
//关于强制转型的补充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");
userDAO.insertUser();
---------------------------------↑-------------------------------↑-----------------------------------
可以看到,insertUser变得非常简洁。数据逻辑清晰可见,对比前面代码控制的事务
管理,以及传统的JDBC操作,相信大家会有一些霍然开朗的感觉。
细心的读者会说,这只不过将代码转移到了配置文件,并没有减少太多的工作量。这点
区别也许并不重要,从应用维护的角度而言,配置化的事务管理显然更具优势。何况,实际
开发中,如果前期设计细致,方法的事务特性确定之后一般不会发生大的变动,之后频繁的
维护过程中,我们只需面对代码中的数据逻辑即可。
上面我们结合JdbcTemplate介绍了Spring中的模板操作以及事务管理机制。Spring
作为一个开放式的应用开发平台。同时也针对其他组件提供了良好的支持。在持久层,
Spring提供面向了Hibernate、ibatis和JDO的模板实现,同样,这些实现也为我们的开发
提供了强有力的支持。
无法保证数据操作的原子性(要么全部生效,要么全部无效),如:
---------------------------------↓-------------------------------↓-----------------------------------
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");
---------------------------------↑-------------------------------↑-----------------------------------
由于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库
中”erica”对应的记录已经被更新,如果第二个操作失败,我们无法使得整个事务回滚到最
初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致
致命错误。
为了实现数据操作的原子性,我们需要在程序中引入事务逻辑,在JdbcTemplate中引入
事务机制,在Spring中有两种方式:
1. 代码控制的事务管理
2. 参数化配置的事务管理
下面就这两种方式进行介绍。
★ 代码控制的事务管理
首先,进行以下配置,假设配置文件为(Application-Context.xml):
---------------------------------↓-------------------------------↓-----------------------------------
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
---------------------------------↑-------------------------------↑-----------------------------------
配置中包含了三个节点:
● dataSource
这里我们采用了apache dhcp组件提供的DataSource实现,并为其配置了
JDBC驱动、数据库URL、用户名和密码等参数。
● transactionManager
针对JDBC DataSource类型的数据源,我们选用了
DataSourceTransactionManager
作为事务管理组件。
如果需要使用基于容器的数据源(JNDI),我们可以采用如下配置:
---------------------------------↓-------------------------------↓-----------------------------------
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/sample</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTrans
actionManager"
/>
---------------------------------↑-------------------------------↑-----------------------------------
userDAO 申明了一个UserDAO Bean,并为其指定了dataSource和
transactionManger资源。
UserDAO对应的代码如下:
---------------------------------↓-------------------------------↓-----------------------------------
public class UserDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =
new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}
---------------------------------↑-------------------------------↑-----------------------------------
可以看到,在insertUser方法中,我们引入了一个新的模板类:
org.springframework.transaction.support.TransactionTemplate。
TransactionTemplate封装了事务管理的功能,包括异常时的事务回滚,以及操作成
功后的事务提交。和JdbcTemplate一样,它使得我们无需在琐碎的try/catch/finally代码
中徘徊。在doInTransaction中进行的操作,如果抛出未捕获异常将被自动回滚,如果成功执行,
则将被自动提交。
这里我们故意制造了一些异常来观察数据库操作是否回滚(通过在第二条语句中更新自
增ID字段故意触发一个异常):
编写一个简单的TestCase来观察实际效果:
---------------------------------↓-------------------------------↓-----------------------------------
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
---------------------------------↑-------------------------------↑-----------------------------------
相信大家多少觉得上面的代码有点凌乱,Callback类的编写似乎也有悖于日常的编程
习惯(虽然笔者觉得这一方法比较有趣,因为它巧妙的解决了笔者在早期自行开发数据访问
模板中曾经遇到的问题)。
如何进一步避免上面这些问题?Spring 的容器事务管理机制在这里即体现出其强大
的能量。
★ 参数化配置的事务管理
在上面的Application-Context.xml增加一个事务代理(UserDAOProxy)配置,同时,
由于事务由容器管理,UserDAO不再需要TransactionManager设定,将其移除:
---------------------------------↓-------------------------------↓-----------------------------------
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
---------------------------------↑-------------------------------↑-----------------------------------
上面的配置中,UserDAOProxy节点配置了一个针对userDAO bean的事务代理(由
target属性指定)。
通过transactionAttributes属性,我们指定了事务的管理策略,即对所有以insert
开头的方法进行事务管理,如果被管理方法抛出异常,则自动回滚方法中的事务,如果成功
执行,则在方法完成之后进行事务提交。另一方面,对于其他方法(通过通配符*表示),
则进行只读事务管理,以获得更好的性能。
与之对应,UserDAO.insertUser的代码修改如下:
---------------------------------↓-------------------------------↓-----------------------------------
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
---------------------------------↑-------------------------------↑-----------------------------------
测试代码修改如下:
---------------------------------↓-------------------------------↓-----------------------------------
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意这里须通过代理Bean"userDAOProxy"获得引用,而不是直接getBean(“userDAO”)
//此外这里还存在一个有关强制转型的潜在问题,请参见Hibernate in Spring一节后
//关于强制转型的补充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");
userDAO.insertUser();
---------------------------------↑-------------------------------↑-----------------------------------
可以看到,insertUser变得非常简洁。数据逻辑清晰可见,对比前面代码控制的事务
管理,以及传统的JDBC操作,相信大家会有一些霍然开朗的感觉。
细心的读者会说,这只不过将代码转移到了配置文件,并没有减少太多的工作量。这点
区别也许并不重要,从应用维护的角度而言,配置化的事务管理显然更具优势。何况,实际
开发中,如果前期设计细致,方法的事务特性确定之后一般不会发生大的变动,之后频繁的
维护过程中,我们只需面对代码中的数据逻辑即可。
上面我们结合JdbcTemplate介绍了Spring中的模板操作以及事务管理机制。Spring
作为一个开放式的应用开发平台。同时也针对其他组件提供了良好的支持。在持久层,
Spring提供面向了Hibernate、ibatis和JDO的模板实现,同样,这些实现也为我们的开发
提供了强有力的支持。
发表评论
-
AJAX与spring mvc交互
2014-10-09 11:08 1134(1)简单交互: <table style=&quo ... -
Spring 使用注解方式进行事物管理
2013-09-12 08:54 797大家在使用spring的注解式事务管理时,对事务的传播行为和 ... -
Spring的事务处理之编程式事务处理
2013-09-11 14:23 1054[Java] view plaincopy ... -
Spring的事务处理之声明式事务处理
2013-09-11 14:05 731[Java] view plaincopy ... -
spring与mybatis三种整合方法
2013-09-10 11:28 797感谢作者的整理,文章转自:http://nirvana19 ... -
Spring 基于Hibernate数据源的SessionFactory配置
2013-09-10 10:55 18911.不用dataSource引入hibernate.cfg ... -
Spring 3.0 注解注入详解
2013-09-10 09:32 696一、各种注解方式 1.@A ... -
Spring 依赖注入原理学习
2013-09-10 09:14 838首先我们来看看 Spring 参考文档的 11.2.6. 执 ...
相关推荐
当使用`JdbcTemplate`结合Spring框架时,可以采用与原生JDBC事务控制类似的方法,但在Spring环境中进行管理。以下是一个使用Druid数据库连接池的示例代码: ```java @RequestMapping("/druidData1") public String ...
在Spring4中,JdbcTemplate与事务管理的结合主要体现在以下几个方面: - **事务回调**:可以使用TransactionCallback接口,在回调方法中执行数据库操作。Spring会自动在事务内部执行这个回调,确保事务的正确性。 ...
本文将详细讲解如何通过JdbcTemplate启用事务管理,并探讨事务的传播机制。 首先,我们要引入Spring的JDBC支持以及相应的数据库驱动。在`pom.xml`或`build.gradle`文件中,我们需要添加以下依赖(这里以Maven为例)...
- **事务的隔离级别**:控制事务与其他事务之间的隔离程度。 - **事务的传播行为**:定义了当前方法执行时如何与现有的事务进行交互。 - **超时时间**:事务的最大执行时间。 - **是否只读**:事务是否只读取数据而...
配制Spring事务和JdbcTemplate使用 配制Spring事务和JdbcTemplate使用
通常情况下,JdbcTemplate本身不直接支持事务,但可以与Spring的事务管理机制相结合,来实现声明式事务管理。这包括使用XML配置或注解的方式来管理事务。不过,如果我们想要手动控制事务,比如在某些特定场景需要...
`JdbcTemplate`提供了事务管理、异常转换等特性,避免了手动处理数据库连接、关闭资源等繁琐工作,提高了代码的可读性和可维护性。 配置多数据源在Spring Boot中主要涉及以下几个步骤: 1. 引入依赖:在`pom.xml`...
jdbcTemplate与事务管理结合使用,可以方便地实现事务控制,尤其是在使用连接池时。 在实际应用中,配置这些库和事务管理,需要在Spring的配置文件中指定数据源、事务管理器等相关设置。例如,使用c3p0时,需要配置...
4. **事务与回滚**:`JdbcTemplate`还提供了事务管理的能力。当在一个事务中执行多条SQL语句时,如果其中一个失败,所有操作都将回滚,确保数据的一致性。你可以通过`JdbcTemplate`的`execute`方法执行一组SQL操作,...
Spring JdbcTemplate支持自动和手动的事务管理。在AOP(面向切面编程)的帮助下,可以在方法级别控制事务的开始、提交和回滚。例如,通过@Transactional注解开启事务,当发生异常时,事务会自动回滚。 五、优势与...
- 避免过度使用`JdbcTemplate`,对于复杂查询和事务,可以考虑使用ORM框架如Hibernate或MyBatis。 - 使用预编译的SQL(PreparedStatement)来防止SQL注入。 - 对于分页查询,确保正确设置分页参数以优化查询性能...
首先,JdbcTemplate的核心理念是通过预编译的SQL语句和参数绑定来防止SQL注入攻击,同时提供事务管理的支持。它提供了大量方法来执行各种数据库操作,如查询、更新、插入和删除等。 使用Spring JdbcTemplate的第一...
在本文中,我们将深入探讨如何使用Spring Boot集成JdbcTemplate与MySQL数据库进行数据操作。Spring Boot以其简化配置和快速启动的特点,已经成为Java开发者的首选框架。而JdbcTemplate是Spring框架的一部分,它提供...
2. **事务管理**:`JdbcTemplate`提供了自动的事务管理功能,可以根据配置决定事务的边界,使得在处理数据库操作时无需手动管理事务。 3. **异常处理**:它将数据库驱动抛出的`SQLException`转换为Spring的`...
3. `spring-jdbc-5.0.0.RELEASE.jar`:包含Spring对JDBC的支持,包括JDBCTemplate和DataSourceTransactionManager,它们是与数据库交互和管理事务的关键。 4. `spring-tx-5.0.0.RELEASE.jar`:提供了事务管理功能,...
JdbcTemplate是Spring JDBC模块的核心组件,它的出现极大地减轻了开发者手动处理JDBC连接、事务管理以及异常处理的工作负担。 **1. 数据源注入与配置** 在使用JdbcTemplate之前,首先需要配置数据源(DataSource)...
4. **事务管理**:如果需要在多个数据库操作之间保持一致性,可以利用JdbcTemplate提供的事务管理功能。你可以使用`@Transactional`注解来声明一个方法需要在事务内执行。 ```java @Service @Transactional public ...
Spring JdbcTemplate是一个强大的工具,它简化了Java应用程序与数据库之间的交互。在Spring框架中,JdbcTemplate作为对原生JDBC API的封装,提供了一种更安全、更易于使用的API,帮助开发者避免了处理连接关闭、异常...
在Spring中,JDBCTemplate默认在每个数据库操作后隐式提交事务,但如果需要更复杂的事务策略,如回滚或嵌套事务,就需要使用spring-tx提供的服务。这使得JDBCTemplate可以在事务边界内安全地执行SQL语句。 5. **...
此外,`JdbcTemplate`支持在一组数据库操作中开启和提交事务,以确保数据的一致性。 ### 总结 `JdbcTemplate`是Spring对JDBC的增强,它极大地简化了数据库操作,降低了数据库访问的复杂性,同时保持了良好的性能。...