一、建立数据库表
1.service代码
@Service
public class UserService {
@Autowired
private UserDao userDao;
//service建一个转账的方法
//模拟李四给张三转账
public void zhuanzhang(){
userDao.jian();
int a = 10/0;
userDao.add();
}
}
2.Dao代码
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int add() {
String sql = "update account set banlance = banlance + ? where username = '张三'";
int update = jdbcTemplate.update(sql, 50);
return update;
}
@Override
public int jian() {
String sql = "update account set banlance = banlance - ? where username = '李四'";
int update = jdbcTemplate.update(sql, 50);
return update;
}
}
这里模拟的是李四给张三转账
3.xml代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="jdbc_tx.service"></context:component-scan>
<!--引入命名空间-->
<context:property-placeholder location="jdbc.properties"/>
<!-- 创建数据库连接池Bean -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${url}" />
<property name="username" value="${uname}" />
<property name="password" value="${password}" />
<property name="driverClassName" value="${driverClassName}" />
</bean>
<!--创建JDBC模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
4.测试代码
@Test
public void testTX(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring_tx.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.zhuanzhang();
}
运行结果:再没有异常的情况下可以正常执行,
但当有异常时就会出现100,50的情况
二、解决(基于注解方式)
配置事务管理器
1.在xml中配置事务管理器,注入数据源,
2.开启事务注解驱动,指定事务管理器
3.在service层上的类加上@Transactional注解。
@Transactional注解的几个属性
@Transactional(
readOnly = false,
rollbackFor = Exception.class,
isolation = Isolation.REPEATABLE_READ,
propagation = Propagation.REQUIRED,
timeout = 500000
)
/**
* readOnly = true, 是否只读:如果是只读,则只能进行读操作,不能写
rollbackFor = Exception.class, 回滚异常
noRollbackFor = NullPointerException.class, 不回滚的异常
isolation = , 事务的隔离级别
propagation = 事务的传播行为
timeout = 超时时间 如果超出了某个时间不提交,则会回滚
spring提供了7中传播行为
*/
三、解决(基于XML方式)
1.在xml中配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2.创建事务通知(增强)
<!--配置通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务属性-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="zhuanzhang*" isolation="DEFAULT" read-only="false" timeout="-1" propagation="REQUIRED" />
<tx:method name="delete*" isolation="DEFAULT" read-only="false" timeout="-1" propagation="REQUIRED" />
<tx:method name="update*" isolation="DEFAULT" read-only="false" timeout="-1" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
3.创建切入点和切面
<!--配置切入点和切面-->
<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="myPoint" expression="execution(* jdbc_tx.service.UserService.*(..))"></aop:pointcut>
<!--配置切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint"></aop:advisor>
</aop:config>
四、完全注解式开发
@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///user_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建 JdbcTemplate 对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
//到 ioc 容器中根据类型找到 dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入 dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager
getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new
DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}