Nutz的 数据库事务

Posted on

Nutz的 数据库事务

1.数据库事务 数据库的事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。一般来讲,隔离性是通过锁机制来实现,而其他三个特性通过日志机制实现。 当一个数据库的某些数据由多个客户端并发访问操作的时候,可能会出现一系列的问题:(1)脏读(dirty read),(2)不可重复读(unrepeatable read),(3)幻象读(phantom read),(4)丢失更新

2.使用Nutz来处理事务 在nutz中使用一个类org.nutz.trans.Trans来处理事务,使用方式如下: Java代码 收藏代码

  1. //TODO 选择事务级别
  2. int level=Connection.TRANSACTION_SERIALIZABLE;
  3. Trans.exec(level, new Atom(){
  4. @Override
  5. public void run() {
  6. //TODO 事务内的操作逻辑
  7. }
  8. });

当然你也可是使用如下默认方式:

Java代码 收藏代码

  1. Trans.exec(new Atom(){
  2. @Override
  3. public void run() {
  4. //TODO
  5. }
  6. });

    在这种情况下,level默认是Connection.TRANSACTION_READ_COMMITTED 注:如果你使用jdbc来直接操作事务,当然你可以在某一个位置设置保存点,如果事务失败,可以回滚到那个点,在nutz中整个事务要么成功,要么失败,全部回滚。如果你希望使用savepoint改怎么办呢,你可以这么用:

Java代码 收藏代码

  1. Dao dao=null;
  2. dao.run(new ConnCallback(){
  3. @Override
  4. public void invoke(Connection conn) throws Exception {
  5. // TODO 在这里面使用Connection来操作
  6. }
  7. });

3.ThreadLocal Nutz在实现Trans这个类的时候用到了ThreadLcoal(方便了使用者存储变量到当前线程。),用来存储用户的每一次事务动作。具体实现请参见源代码类org.nutz.trans.Trans。

来源: [http://amosleaf.iteye.com/blog/548337](http://amosleaf.iteye.com/blog/548337)

4、事务的嵌套

设置事务的级别

在 JDBC 的 java.sql.Connection 接口中定义的 setTransactionIsolation 函数可以设置事务的级别Nutz.Dao 也提供另外一个静态函数,允许你设置事务的级别:

Trans.exec 的函数声明 public static void exec(int level, Atom... atoms);

这里的第一个参数 level 和 java.sql.Connection 接口中的 setTransactionIsolation 规定的 level 是一样的。下面是在 java.sql.Connection 里面关于 level 参数的 JDoc 说明:

它可以是下列常量中的任意一个值:

  • Connection.TRANSACTION_READ_UNCOMMITTED
  • Connection.TRANSACTION_READ_COMMITTED
  • Connection.TRANSACTION_REPEATABLE_READ
  • Connection.TRANSACTION_SERIALIZABLE

注意: 不能使用常量 Connection.TRANSACTION_NONE,因为它的意思是“不支持事务”

关于 level 参数的更多说明,请参看java.sql.Connection 的文档)

不同的数据库,对于 JDBC 事务级别的规范,支持的力度不同。请参看相应数据库的文档,已 确定你设置的数据库事务级别是否被支持。

/#Top

事务的嵌套

Nutz 的事务模板可以嵌套吗? 答案是肯定的。事实上,Nutz 支持事务模板的无限层级嵌套。

这里,如果每一层嵌套,指定的事务级别有所不同,不同的数据库,可能引发不可预知的错误。所以,嵌套的事务模板的事务,将以最顶层的事务为级别为标准。就是说,如果最顶层的事务级别为 'TRANSACTION_READ_COMMITTED',那么下面所包含的所有事务,无论你指定什么样的事务级别,都是 'TRANSACTION_READ_COMMITTED', 这一点,由抽象类 Transaction 来保证。其 setLevel 当被设置了一个大于 0 的整数以后,将不再 接受任何其他的值。

你可以通过继承 Transaction 来修改这个默认的行为,当然,这个行为修改一般是没有必要的。

另外,你还可能需要知道,通过 Trans.setup 方法,能让整个虚拟机的 Nutz 事务操作都使用你的 Transaction 实现

下面我给出两个例子:

最外层模板决定了整个事务的级别: Trans.exec(Connection.TRANSACTION_READ_COMMITTED, new Atom(){ public void run(){ dao.update(xxx); dao.update(bbb); // 在下层模板,虽然你指定了新的事务级别,但是这里的事务级别还是 // 'TRANSACTION_READ_COMMITTED'。在一个事务中,级别一旦设定就不可更改 Trans.exec(Connection.TRANSACTION_SERIALIZABLE, new Atom(){ public void run(){ dao.update(CCC); dao.update(EEE); } }); } });

让整个函数都是事务的:

public void updatePet(final Pet pet){ Trans.exec(new Atom(){ public void run(){ dao.update(pet); dao.update(pet.getMaster()); } }); } // 在另外一个函数里,可以这么使用 public void updateDogAndCat(final Pet dog, final Pet cat){ Trans.exec(new Atom(){ public void run(){ updatePet(dog); updatePet(cat); } }); }

来源: [http://code.google.com/p/nutz/wiki/dao_transaction](http://code.google.com/p/nutz/wiki/dao_transaction) 以上需要注意的几个细节,文档还没提及: 1. 数据库连接池的AutoCommit属性 对于我见到的大部分连接池和数据库驱动,默认情况下AutoCommit=true,应该是为了性能 这就导致如果用户不自行设置的话,Trans的大部分操作都是不可回滚的.故,如果使用Trans,那么务必设置AutoCommit

2. 多个数据源的事务 大部分情况下,用户都不是使用XA驱动,故,多数据源的事务提交,在最后的提交阶段出错的话,已经执行commit操作的数据源,是不可能回滚的

3. 子线程的事务 考虑下面的代码: Trans.exec(new Atom(){ public void run() { dao.insert(pet); new MySuperPowerThread().start(); dao.count(Pet.class); }});

那么MySuperPowerThread的代码并不是在事务模板中执行的,因为这里的事务不会被子线程继承

4. 返回值问题(更新了) 使用Molecule Molecule mc = new Molecule() { public void run() { dao.insert(pet); setObj(dao.count(Pet.class)); }};Trans.exec(mc);System.out.println(mc.getObj());

来源: [http://wendal.net/324.html](http://wendal.net/324.html)

希望本站内容对您有点用处,有什么疑问或建议请在后面留言评论
转载请注明作者(RobinChia)和出处 It so life ,请勿用于任何商业用途
无觅关联推荐,快速提升流量