事务的本质:让程序像我们看到的那样执行。
数据库事务就是对于界定为同一个事务的一组数据库操作,要么同时成功,要么同时失败,不可能出现部分成功的中间状态。
对于JDBC原生事务,首先要设置自动提交为false:connection.setAutoCommit(false),如果整个执行过程没有异常则提交事务commit,否则就回滚rollback。对于原生态的jdbc事务,编码显得非常繁琐,并且对于整个系统的共性业务,特别适合用AOP的方式来实现。
下面说到重点了,TeaFramework事务实现。
1、事务的使用应该尽量简单,在方法或者class上加一个注解便可搞定,对于class有事务注解,那么该class所有方法都有进行事务控制。
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Transcation {
}
2、事务的传播
事务的传播描述的是多个事务嵌套的问题,对于大部分场景而言,顶层方法有事务,则子事务被纳入当前事务,这种场景占80%,那么TeaFramework只实现这种事务传播。
请看具体的代码
public class TranscationProxy extends AbstractProxy {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void invoke(Proxy proxy) throws Throwable {
BeanProxy beanProxy = (BeanProxy) proxy;
boolean classHasTranscationAnnotation = beanProxy.getObj().getClass().getSuperclass()
.isAnnotationPresent(Transcation.class);
boolean methodHasTranscationAnnotation = beanProxy.getMethod().isAnnotationPresent(Transcation.class);
if (TranscationThreadVariable.get() == null
&& (classHasTranscationAnnotation || methodHasTranscationAnnotation)) {// 如果类或者方法有Transcation注解则进入
try {
before(proxy);
proxy.invoke(proxy);
after(proxy);
} catch (Throwable e) {
exception(proxy);
throw e;
} finally {
end(beanProxy);
}
} else {
proxy.invoke(proxy);
}
}
@Override
public void before(Proxy proxy) {
try {
TranscationThreadVariable.set(true);
logger.debug("开启事务");
if (ConnectionThreadVariable.getConnetion() == null) {
Connection connection = DataSourceHelp.getConnection();
connection.setAutoCommit(false);
ConnectionThreadVariable.setConnetion(connection);
}
} catch (Exception e) {
throw new TranscationException(e);
}
}
@Override
public void after(Proxy proxy) {
try {
logger.debug("提交事务");
ConnectionThreadVariable.getConnetion().commit();
} catch (Exception e) {
throw new TranscationException(e);
}
}
@Override
public void exception(Proxy proxy) {
try {
logger.debug("回滚事务");
ConnectionThreadVariable.getConnetion().rollback();
} catch (Exception e) {
throw new TranscationException(e);
}
}
@Override
public void end(Proxy proxy) {
try {
logger.debug("关闭连接");
ConnectionThreadVariable.getConnetion().close();
} catch (Exception e) {
throw new TranscationException(e);
} finally {
ConnectionThreadVariable.clearThreadVariable();
TranscationThreadVariable.clearThreadVariable();
}
}
}
这里本质上是实现了一个代理类,用AOP的思路来实现
1、before:在事务开启之前,获取数据库连接,并设置自动提交为false
2、after:执行过程如果没有任何异常,则提交事务
3、exception:执行过程发生异常,则回滚事务
4、end:执行结束,关闭数据库连接,归还给连接池
那么事务的传播在哪里实现的呢?仅仅只有一行代码TranscationThreadVariable.set(true),这行代码标示了当前线程中事务的状态,如果事务已经由上层方法开启,则下面所有的数据库操作与开启事务的方法共用一个数据库连接connection,那么就被纳入了一个事务。
来看一个例子,在insert方法上加上@Transcation注解
@TeaDao("testDao")
public interface TestDao {
@Transcation
@GetPrimaryKey(sql = "select s_users.nextval from dual", primaryKeyProperty = "id")
@SQL("insert into users(id,name,password,createdate) values(#id#,#name#,#password#,#createdate#)")
public int add(Map<String, Object> map);
@DynamicSQL
public int update();
@SQL("delete from users")
public int deleteUserById();
@SQL("select * from users")
public List<User> getAllUser();
@DynamicSQL
public List<User> findUser();
}
执行结果:
这就是TeaFramework事务的实现过程。
项目地址:https://git.oschina.net/lxkm/teaframework
博客:https://blog.youkuaiyun.com/dong_lxkm