基于Eclipse Maven的Spring4/Spring-MVC/Hibernate4整合之四:JdbcTemplate的事务管理

来源:互联网 发布:live for speed mac 编辑:程序博客网 时间:2024/05/16 12:44

     JdbcTemplate自身是不具备事务功能的,而需要通过TransactionTemplate r的callback执行Jdbctemplate才能实现事务管理。

     为了方便使用,我们可以自定义一个带有事务管理的TransJdbcTemplate类,通过注解方式注入了Spring数据库事务器 dsTm,此类提供了事务执行方法doTransactionBatch:

package com.freestyle.common.spring;import javax.annotation.Resource;import javax.sql.DataSource;import org.springframework.context.annotation.DependsOn;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.support.TransactionCallback;import org.springframework.transaction.support.TransactionTemplate;/**** * 带有事务管理的JdbcTemplate * @author dgmislrh * */@DependsOn({"dsTransactionManager"})//@Repository("transJdbcTemplate")public class TransJdbcTemplate extends org.springframework.jdbc.core.JdbcTemplate{@Resource(name="dsTransactionManager")private org.springframework.jdbc.datasource.DataSourceTransactionManager dsTm;public static interface TransCallback{public void onExecute(JdbcTemplate pvJt);}public TransJdbcTemplate(DataSource dataSource) {super (dataSource);}/**** * 若需要回滚事务,在onExecute里面throw runtimeexception即可 * @param lvCallback */public void doTransactionBatch(final TransCallback lvCallback){TransactionTemplate  lvTt=new TransactionTemplate (dsTm);lvTt.execute(new TransactionCallback<Boolean>() {@Overridepublic Boolean doInTransaction(TransactionStatus arg0) {JdbcTemplate lvJt=(JdbcTemplate) ContextHolder.getBean("jdbcTemplate");lvCallback.onExecute(lvJt);return true;}});}}

   然后打开spring-db.xml,在里面配置这个类和spring的数据库事务管理器:

<bean id="dsTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">          <property name="dataSource" ref="dataSource" />             </bean>    <!-- 配置具备事务管理的Jdbc Template -->    <bean id="transJdbcTemplate" class="com.freestyle.common.spring.TransJdbcTemplate" >    <constructor-arg ref="dataSource"></constructor-arg></bean>  


接下来修改HibernateController.java,写些测试代码,先写入new value,再进行两个case来演示程序错误和业务检查不通过引起的事务回滚,最后回滚成功,重新获取fa_name的值还是new value:

public class HibernateController implements org.springframework.web.servlet.mvc.Controller {// @Resource(name="hibernateUserDao")// private HibernateUserDao lvDao;// @Resource(name="hibernateUserDao")@Resource(name = "hibernateUserDao")protected IHibernateEntityDao<TaUser> mvDao;@Resource(name = "hUserBaseDao")protected IHibernateEntityDao<TaUser> mvBaseDao;@RequestMapping("/test")public ModelAndView test(@RequestParam(value = "name", defaultValue = "World") final String name)throws SQLException {System.out.println("Hello " + name);Map<String, Object> lvMap = new HashMap<String, Object>();/* * TaUser lvUser= lvDao.getUser("dgmislrh"); if (lvUser!=null){ * System.out.println(lvUser.getFaName()); } */StringBuilder lvSb = new StringBuilder();TransJdbcTemplate lvJt = (TransJdbcTemplate) ContextHolder.getBean("transJdbcTemplate");lvJt.doTransactionBatch(new TransCallback() {@Overridepublic void onExecute(JdbcTemplate pvJt) {pvJt.update("update ta_user set fa_name='new value' where fa_login=?", new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps) throws SQLException {ps.setString(1, name);}});}});lvSb.append("成功设置fa_name为new value.<br/>");// case 1: 程序错误导致回滚,保证了数据完整性try {lvJt.doTransactionBatch(new TransCallback() {@Overridepublic void onExecute(JdbcTemplate pvJt) {// 第一条SQL成功执行pvJt.update("update ta_user set fa_name='new value 1' where fa_login=?",new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps) throws SQLException {ps.setString(1, name);}});// 第二条SQL语法错误,会导致上面的执行结果无效(事务回滚)pvJt.update("la la update ta_user set fa_name='new value 2' where fa_login=?",new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps) throws SQLException {ps.setString(1, name);}});}});} catch (Exception e) {lvSb.append("执行错误:" + e.getMessage() + "<br/>");}// case 2: 根据需要用抛出exception方式触发,回滚try {lvJt.doTransactionBatch(new TransCallback() {@Overridepublic void onExecute(JdbcTemplate pvJt) {// 第一条SQL成功执行pvJt.update("update ta_user set fa_name='new value 3' where fa_login=?",new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps) throws SQLException {ps.setString(1, name);}});if (pvJt != null) { // 模拟事后的业务检查失败,抛出exception以回滚throw new RuntimeException("我长得太帅,不通过<br/>");}}});} catch (Exception e) {lvSb.append("业务检查不通过:" + e.getMessage());}TaUser lvUser = mvDao.get(name);lvSb.append("最后fa_name的值为"+lvUser.getFaName());lvMap.put("result", lvSb.toString());/* * TaUser lvUser=mvDao.get(name); lvUser.setFaName("new name 22222"); * mvBaseDao.save(lvUser); lvUser=mvDao.get(name); if (lvUser!=null){ * System.out.println(lvUser.getFaName()); lvMap.put("result", * lvUser.getFaName()); } */return new ModelAndView("/result", lvMap);}

启动tomcat,在浏览器地址栏输入http://localhost/gpchat/hibernate/test?name=dgmislrh,网页显示:

成功设置fa_name为new value.执行错误:PreparedStatementCallback; bad SQL grammar [la la update ta_user set fa_name='new value 2' where fa_login=?]; nested exception is org.postgresql.util.PSQLException: ERROR: syntax error at or near "la" 位置:1业务检查不通过:我长得太帅,不通过最后fa_name的值为new value



0 0