github仓库链接:https://github.com/chegy218/ssm-review/tree/master/transacction_sql
下面介绍一下数据库事务管理机制:
例如银行转账。当从A账户向B账户转1000元后银行系统会从A账户上扣除1000元,而在B账户上增加1000元,这是正确处理的结果。
一旦银行系统出错了怎么办,这里假设发生两种情况:
(1)A账户少了1000元,但B账户却没有多出1000元
(2)B账户多了1000元,但A账户却没有被扣钱
客户和银行都不愿意看到上面两种情况。那么有没有措施保障转账的顺利进行?这种措施就是数据库事务管理机制。
本文分三个层面讲解
1,JdbcTemplate 数据库编程式互联网编程的基础。jdbcTemplate是Spring框架为开发者提供的JDBC模板模式。但工作中更多的时候是使用Hibernate框架和MyBatis框架进行数据库编程。想一下,这是为什么JDBC开发时不常用? jdbcTemplate没有实现事务管理,只是单纯的数据库编程,通过下面的demo即可理解。JdbcTemplate
编程式事务管理
声明式事务管理
(1)数据访问层
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Autowired
//使用配置文件中的JDBC模板
private JdbcTemplate JdbcTemplate;
/**
* 更新方法,包括添加,修改,删除
*/
@Override
public int update(String sql, Object[] param) {
return JdbcTemplate.update(sql,param);
}
/**
* 查询方法
*/
@Override
public List<User> query(String sql, Object[] param) {
RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class);
return JdbcTemplate.query(sql, rowMapper,param);
}
}
(2),xml配置jdbc
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- MySQL数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- 连接数据库的URL -->
<property name="url" value="jdbc:mysql://localhost:3306/test4?characterEncoding=utf8&useSSL=true"/>
<!-- 连接数据库的用户名 -->
<property name="username" value="root"/>
<!-- 连接数据库的密码 -->
<property name="password" value="123456"/>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
(3),JAR包导入(整个demo的JAR,下面就不再赘述了)
(4)com.test里测试类(从上面的github路径查看源代码,下面就不再赘述。)
在代码中显示调用beginTransaction,commit,rollback等于事务处理相关的方法,这就是编程式事务管理。当只有少数事务操作时,编程事务管理才合适。
与JdbcTemplate对比:在JdbcTemplate的基础上增加了事务管理,为了解决application与数据库交互时(增删改查),可能出现的因中断问题导致的事件。
(1),基于底层API的编程事务管理
1.1xml配置
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 为数据源添加事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref="dataSource"></property>
</bean>
1,2数据访问类
@Repository
public class CodeTransaction {
//使用配置文件中的JDBC模板
@Autowired(required=true)
private JdbcTemplate jdbcTemplate;
//DataSourceTransactionManger是PlatformTransactionManager接口的实现类
@Autowired
private DataSourceTransactionManager txManager;
public String test(){
//默认事务定义,例如隔离级别,传播行为等
TransactionDefinition tf = new DefaultTransactionDefinition();
//开启事务ts
TransactionStatus ts = txManager.getTransaction(tf);
String message = "执行成功,没有事务回滚!";
try {
//删除表中数据
String sql = " delete from user ";
//添加数据
String addsql = " insert into user values(?,?,?) ";
Object param[] = { 21, "chegy122","男"};
//先删除数据
jdbcTemplate.update(sql);
//添加一条数据
jdbcTemplate.update(addsql,param);
//添加相同的一条数据,使主键重复
jdbcTemplate.update(addsql,param);
//提交事务
txManager.commit(ts);
} catch (Exception e) {
//出现异常,事务回滚
txManager.rollback(ts);
message = "主键重复,事务回滚!";
e.printStackTrace();
}
return message;
}
}
(2)基于TransactionTemplate的编程式事务管理
<!-- 基于TransactionTemplate的编程式事务管理 -->
<!-- 为事务管理transactionManager创建transactionTemplate -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
其实事务管理基于JdbcTemplate(此demo)
3,声明式事务管理Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
与编程式事务管理对比:编程式中掺杂事务处理的代码,侵入性和耦合教高。声明式只需相关事务规则声明便可将事务规则应用到业务逻辑中。
但唯一不足就是,其最细粒度只能作用到方法级别,无法做到像编程式事务管理那样可以作用到diam块级别。但声明式事务也可以通过变通的方法解决。思考一下如何解决?
详细demo请看github链接。