spring 事务开发
一、事务的ACID特性
原子性atomicity:确保动作要不全部完成要么完全不起作用
一致性consistency:数据和资源处于一种满足业务规则的一致性状态中
隔离性isolation:用户的操作不能混淆
持久性durability:一旦事务完成,无论发生什么系统错误,他的结果都不应该受影响
二、事务的分类
1、编程式事务(DAO实现)
package com.zzxtit.spring.tx.anno; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; public class StuCardDaoImpl implements StuCardDao{ @Autowired private JdbcTemplate jt; /** * 根据学生卡编号查询学生卡信息 */ @Override public void updateStuCardByCardNo(StuCard sc) { // TODO Auto-generated method stub jt.update("update stu_card set money = ? where card_no = ?", sc.getMoney(), sc.getStuCardNo()); } @Override public StuCard getStuCardInfoById(String cardNo) { // TODO Auto-generated method stub RowMapper<StuCard> rm = new BeanPropertyRowMapper<StuCard>(); return jt.queryForObject("select card_no stuCardNo, money from stu_card where card_no = ?", rm, cardNo); } }
/* public void payCard(){ * * class.forname(""); * Connection conn=null; * conn=driverManager.getConnection(url,user,password); * Statement state=conn.creatStatement(); * conn.setAutoCommit(false);手动提交事务 * stat.executeUpdate(sql);把钱加在商户上 * stat.executeUpdate(sql);把钱从学生账户扣除 * if(扣钱失败){ * conn.rollback();回滚事务 * }else{ * conn.commit;提交事务 * } * } *
初始化配置文件
在IOC容器中声明transactionManager(事务管理器)
编程式事务管理模板
将管理模板注入到service里面
开启事务
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> <context:component-scan base-package="com.zzxtit.spring.jdbc"></context:component-scan> <context:property-placeholder location="/springAOP/config/DB.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${mysql_driver}"></property> <property name="url" value="${mysql_url}"></property> <property name="username" value="${mysql_username}"></property> <property name="password" value="${mysql_passwd}"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" value="#{dataSource}"></property> </bean> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg index="0" ref="dataSource"></constructor-arg> <!-- 因为只有一个参数 所以不论用名字顺序都可以--> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg name="dataSource" ref="dataSource"></constructor-arg> </bean> <bean id="transcationTemplate" class="org.springframework.jdbc.core.namedParameterJdbcTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> <!-- name 是目标类里的属性值 --> </beans>
和事务相关的文件在program文件中
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> <!-- 通过import标签引入其他上下文配置文件 --> <import resource="ApplicationContext-jdbc.xml"/> <bean id="stuCardDao" class="com.zzxtit.spring.tx.program.stuCardDaoImpl"> <property name="jt" ref="jdbcTemplate"></property> </bean> <bean id="stuCardService" class="com.zzxtit.spring.tx.program.StuCardServiceImpl"> <property name="scDao" ref="stuCardDao"></property> <property name="transactionTemplate" ref="transcationTemplate"></property> </bean> </beans>
package com.zzxtit.spring.tx.program; import java.math.BigDecimal; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import com.zzxtit.spring.tx.exception.NoEnoughMoneyException; import com.zzxtit.spring.tx.program.stuCard.StuCard; public class StuCardServiceImpl implements stuCardService{ private StuCard scDao; private TransactionTemplate transactionTemplate; /** * 转账支付,当金额不足时,抛出异常。 * @param targetCardNo 目标账号 * @param sourceCardNo 源账号 * @param money 转账金额 */ //匿名内部类引用外部对象时需要定义成final类型的 public void transaferMoney(final String targetCardNo, final String sourceCardNo, final String money) { transactionTemplate.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { StuCard sourceCard = scDao.getStuCardInfoById(sourceCardNo); StuCard targetCard = scDao.getStuCardInfoById(targetCardNo); //修改后勤人员信息 sourceCard.setMoney(sourceCard.getMoney().subtract(new BigDecimal(money))); targetCard.setMoney(targetCard.getMoney().add(new BigDecimal(money))); scDao.updateStuCardByCardNo(targetCard); if(sourceCard.getMoney().compareTo(new BigDecimal("0")) < 0){ throw new NoEnoughMoneyException("账户余额不足,请充值。。。。"); } scDao.updateStuCardByCardNo(sourceCard); System.out.println("支付完成!商品购买成功!!!!!"); return null; } }); }
2、声明式事务(XML 配置的方式 )
初始化配置文件 加入命名空间
加入事务的传播属性
配置切入点 (作用在那些类上面) 作用在哪些方法上
配置transactionManager事务作用在哪个管理器上面
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/aop/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> <!-- 通过import标签引入其他上下文配置文件 --> <import resource="ApplicationContext-jdbc.xml"/> <bean id="stuCardDao" class="com.zzxtit.spring.tx.xml.stuCardDaoImpl"> <property name="jt" ref="jdbcTemplate"></property> </bean> <bean id="stuCardService" class="com.zzxtit.spring.tx.xml.StuCardServiceImpl"> <property name="scDao" ref="stuCardDao"></property> </bean> <!-- 事务的传播属性的配置 --> <!-- jdbc里的管理器管理,此时的传播属性为以下 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"></tx:method> <tx:method name="modify*" propagation="REQUIRED"></tx:method> <tx:method name="edit*" propagation="REQUIRED"></tx:method> <tx:method name="delet*" propagation="REQUIRED"></tx:method> <tx:method name="transfer*" propagation="REQUIRED"></tx:method> <tx:method name="query*" propagation="REQUIRED" read-only="true"></tx:method> <tx:method name="select*" propagation="REQUIRED" read-only="true"></tx:method> <tx:method name="find*" propagation="REQUIRED" read-only="true"></tx:method> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut expression="execution(* com.zzxtit.spring.*.xml.*.*(..))" id="txPointcut"/> <!-- * com.zzxtit.spring.*.service.*.*(..)) --> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/> </aop:config> </beans>
package com.zzxtit.spring.tx.xml; import java.math.BigDecimal; import com.zzxtit.spring.tx.exception.NoEnoughMoneyException; public class StuCardServiceImpl implements StuCardService { private StuCardDao scDao; /** * 转账支付,当金额不足时,抛出异常。 * * @param targetCardNo 目标账号 * @param sourceCardNo 源账号 * @param money 转账金额 */ public void transaferMoney(String targetCardNo, String sourceCardNo, String money) { StuCard sourceCard = scDao.getStuCardInfoById(sourceCardNo); StuCard targetCard = scDao.getStuCardInfoById(targetCardNo); // 修改后勤人员信息 sourceCard.setMoney(sourceCard.getMoney().subtract(new BigDecimal(money))); targetCard.setMoney(targetCard.getMoney().add(new BigDecimal(money))); scDao.updateStuCardByCardNo(targetCard); if (sourceCard.getMoney().compareTo(new BigDecimal("0")) < 0) { throw new NoEnoughMoneyException("账户余额不足,请充值。。。。"); } scDao.updateStuCardByCardNo(sourceCard); System.out.println("支付完成!商品购买成功!!!!!"); } /** * @return the scDao */ public StuCardDao getScDao() { return scDao; } /** * @param scDao the scDao to set */ public void setScDao(StuCardDao scDao) { this.scDao = scDao; } }
3、 声明式事务(注解式)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/context/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> <!-- 通过import标签引入其他上下文配置文件 --> <import resource="ApplicationContext-jdbc.xml"/> <context:component-scan base-package="com.zzxtit.spring.*.anno"></context:component-scan> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
@Repository public class StuCardDaoImpl implements StuCardDao{ @Autowired private JdbcTemplate jt; /** * 根据学生卡编号查询学生卡信息 */ @Override public void updateStuCardByCardNo(StuCard sc) { // TODO Auto-generated method stub jt.update("update stu_card set money = ? where card_no = ?", sc.getMoney(), sc.getStuCardNo()); } @Override public StuCard getStuCardInfoById(String cardNo) { // TODO Auto-generated method stub RowMapper<StuCard> rm = new BeanPropertyRowMapper<StuCard>(); return jt.queryForObject("select card_no stuCardNo, money from stu_card where card_no = ?", rm, cardNo); } }
package com.zzxtit.spring.tx.anno; import java.math.BigDecimal; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.zzxtit.spring.tx.exception.NoEnoughMoneyException; @Service public class StuCardServiceImpl implements StuCardService { @Autowired private StuCardDao scDao; /** * 转账支付,当金额不足时,抛出异常。 * * @param targetCardNo 目标账号 * @param sourceCardNo 源账号 * @param money 转账金额 */ @Transactional(propagation=Propagation.REQUIRED, timeout=5 ) public void transaferMoney(String targetCardNo, String sourceCardNo, String money) { StuCard sourceCard = scDao.getStuCardInfoById(sourceCardNo); StuCard targetCard = scDao.getStuCardInfoById(targetCardNo); // 修改后勤人员信息 sourceCard.setMoney(sourceCard.getMoney().subtract(new BigDecimal(money))); targetCard.setMoney(targetCard.getMoney().add(new BigDecimal(money))); scDao.updateStuCardByCardNo(targetCard); if (sourceCard.getMoney().compareTo(new BigDecimal("0")) < 0) { throw new NoEnoughMoneyException("账户余额不足,请充值。。。。"); } try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } //超时设置 scDao.updateStuCardByCardNo(sourceCard); System.out.println("支付完成!商品购买成功!!!!!"); } }
事务的传播行为:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
三、spring具名参数
将named parameterjdbc配置到spring ioc容器里面
<bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg index="0" ref="dataSource"></constructor-arg> <!-- 因为只有一个参数 所以不论用名字顺序都可以--> </bean>
将属性注入到dao里面
(或者用反射将属性的值映射成一个map)
private NamedParameterJdbcTemplate npjTemplate; pubilc void insterUserInfoByNJP(SysUserInfo su) { String sql="insert into t_sys_user (user_name, passwd, salt, real_name, avatar, phone, email, gender, create_time) " + "values (userName:, passwd:, salt:, realName:, avatar:, phone:,email:, gender:, now())"; Map<String,Object> paramMap=new HashMap<String,Object>(); paramMap.put("username", su.getUserName()); npjTemplate.update(sql, paramMap); } }
当需要注入很多字段时使用具名函数
ctrl shift R找类 输入类名 找src里的类
ctrl shift T 找jar包里的类

浙公网安备 33010602011771号