前言
项目框架主要是spring,持久层框架没有用mybtis,用的是spring 的jdbc;
业务需求:给应用添加领域(一个领域包含多个应用,一个应用可能属于多个领域,一般而言一个应用只属于一个领域),要求是给应用添加领域的时候,先将该应用已有的领域都删除,之后再将选中的领域添加到数据库;
为了减少准备工作,我利用了以前的代码和数据建模,那么就成了:添加person的时候先删除已存在name为新添加person的name的person,再添加新person,说直白点就是:添加name为zhangsan的person,那么先删除数据库中name为zhangsan的所有person信息,然后再将新的zhangsan的person信息添加到数据库中;
环境搭建过程我就不写了,完整代码会以附件形式上传;
注意:druid连接池一般而言,jdbc设置成自动提交,不设置的话,默认也是自动提交(有兴趣的朋友可以去看下druid连接池的源码)
jdbcTemplate自动提交
先来验证下,当前jdbcTempalte是否是自动提交的,如何验证了,我可以在jdbcTemplate执行完之后抛出一个异常,代码如下
public int deleteOnePerson(String name) {
int count = jdbcTemplate.update(DELETE_ONE_PERSON, new Object[]{name}); // jdbcTemplate执行完成
count = count / 0; // 抛出RuntimeException
return count;
}
没有配置事务
View Code
那么如果直接像如下方式来处理先删后加是不行的,如果删成功添加失败,那么数据库的数据却只是删了而没有添加成功
public int insertOnePerson(String name, int age) {
int result = 0;
int count = jdbcTemplate.update(DELETE_ONE_PERSON, new Object[]{name});
if(count >= 0) // =0的情况是数据库之前不存在该name的person信息
{
result = jdbcTemplate.update(INSERT_ONE_PERSON, new Object[]{name,age});
}
return result ;
}
手动提交事务
为了保证事务一致性,第一时间想到了jdbcTemplate是否有事务相关设置,然而并没有发现,但是发现了jdbcTemplate.getDataSource().getConnection(),于是飞快的写了如下代码:
手动提交1
public int insertOnePerson(String name, int age) {
int result = 0;
try {
jdbcTemplate.getDataSource().getConnection().setAutoCommit(false);
int count = jdbcTemplate.update(DELETE_ONE_PERSON, new Object[]{name});
if(count >= 0) // =0的情况是数据库之前不存在该name的person信息
{
result = jdbcTemplate.update(INSERT_ONE_PERSON, new Object[]{name,"1ac"});
}
jdbcTemplate.getDataSource().getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
try {
jdbcTemplate.getDataSource().getConnection().rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
jdbcTemplate.getDataSource().getConnection().setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
return result ;
}
本以为实现事务一致性,可执行结果如下:
发现没有实现事务一致性,这是为什么??????? 这里先留个悬念,大家好好思考下;当时我也没去仔细研究,因为完成任务才是第一要紧事,紧接着写出了如下代码:
手动提交2
public int insertOnePerson(String name, int age) {
int result = 0;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = jdbcTemplate.getDataSource().getConnection();
if(conn != null)
{
conn.setAutoCommit(false);
pstmt = conn.prepareStatement(DELETE_ONE_PERSON);
pstmt.setString(1, name);
int count = pstmt.executeUpdate();
pstmt.close();
if(count >= 0)
{
pstmt = conn.prepareStatement(INSERT_ONE_PERSON);
pstmt.setString(1, name);
pstmt.setString(2, "1adh"); // 引发异常
result = pstmt.executeUpdate();
}
conn.commit();
}
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
System.out.println("rollback failed..");
e1.printStackTrace();
}
} finally {
try{
conn.setAutoCommit(true);
if(pstmt != null){
pstmt.close();
}
if(conn != null){
conn.close();
}
}catch(SQLException e){
}
}
return result ;
}
诡异的事情来了,居然和上面的情况一样:删除成功,添加失败! 我的天老爷,这是怎么回事????
瞬间懵逼了,怎么回事?代码怎么改都不行!!!
mysql引擎
查看数据库引擎,发现引擎是MyISAM! 瞬间爆炸!!!!
将引擎改成InnoDB后,手动提交2的代码是能够保证事务一致性的,那么手动提交1的代码是不是也能保证事务一致性了? 此处再留一个悬念,希望各位观众老爷们好好思考下。
事务自动管理
任务虽然完成了,可是无论是手动提交2,还是手动提交1(姑且认为能保证事务一致性),代码的try catch简直让人无法接受;映像中,spring有事务管理,那么就来看看事务交给spring如何实现
配置事务管理器:
View Code
配置事务
@Transactional
public int insertOnePerson(String name, int age) {
int result = 0;
int count = jdbcTemplate.update(DELETE_ONE_PERSON, new Object[]{name});
if(count >= 0)
{
result = jdbcTemplate.update(INSERT_ONE_PERSON, new Object[]{name,"l123a"});
}
return result ;
}
执行结果如下: