`
hgq0011
  • 浏览: 539582 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

细粒度处理事务,尽快的结束事务

    博客分类:
  • Jdbc
阅读更多

      在搭建系统的架构时我们采用了ssh+ajax等方式构建的。我一在和大家说我们要层次分明,思路清晰,可现在都比较糟糕。

       比如:JSP页面用来显示数据的,css用来美化页面,JS用来控制页面的。现在很多页面中什么都有了,臭味很多。

       在后台我们也分了action,service,dao层,原本action用来控制调度的,service用来处理相关的业务逻辑的,DAO中用来CRUD数据的。可现在出现了action包裹着一部分逻辑,service就非常简单了,就是用来调用DAO中的方法,而DAO中的方法即包裹了业务处理逻辑又包裹了CRUD数据处理。而且有的业务逻辑非常的复杂,涉及到的表操作很多,比如有

//结合spring支持hibernate
Session session = getSession();

//可以能会处理的一些东西
//1)通过hibernate方法select数据
//2)通过hibernate方法update数据
//3)通过hibernate方法delete数据
//4)通过hibernate方法insert数据

//通过session获取Connection,使用JDBC进行数据处理
Connection con = session.getConnection();
//因为有一些逻辑很负责一个select语句涉及的表太多,所以用JDBC来处理。

String sql = "select a ,b ,c ,d from A ,B,C,D where a = ? and b=?";
//反正类似的操作吧,就是关连来多。

 类似上面的方式,大多数同学在大多数的时候都是这么弄的。我觉得这样做就把业务逻辑和数据处理混淆了,方法太臃肿了,有着浓浓的臭味,不便于维护。XP中提倡面向接口编程、分层、短小的方法。它这么一个长长的方法占用一个连接的时间太长(也就是整个事务的时间延长了),那么当其他的用户对相关的表进行请求时,就会出于等待的状态,资源的竞争,如果长时间是这样死锁就出现了。:(

 

     我一般会把他们分布在不同的方法中。

//对应表的相关操作
public interface DAO{
     public List get##(String s);
     public void update##(String ...);
     public void delete##(String ...);
     public void insert##(String ...);
     public List find##(String...);

}


public class Service{
    public DAO dao = .......;//注入DAO对象。

    //结合DAO执行相应的业务处理操作
    public List update###(){
           dao.get(s);
           dao.update##(String ...);
           dao.delete##(String ...);
           dao.insert##(String ...);

           //处理更复杂的业务逻辑。
           logice();

           return dao.find##(String...);
   } 

    public void logice(){  
          //to do something  
  } 
   
}

 这样我的每一个DAO中的方法就会用到不同的SESSION(不同的CONNECTION),是这样的吗?但是我是通过SPRING对service层进行事务处理的呀,那是不是说明两种方式都会要占用同样的事务处理资源?

 

     看到那些贫血的SERVICE我就郁闷,现在我有检查代码是否存在问题我也迷茫,这事情做的太少了。很多时候我们只顾一直往前跑,没有时间回头看。其实,我们要经常的code view,使用TDD开发模式,用XP的小步发布,这样不要让代码的味道变的太坏,也对自己写的代码充满信心,和用户交流底气十足。开发出来的系统,用户满意,市场行情看涨。:)

请您提出宝贵的意见。

 

 

更新:2008-10-10 22:00

 

我把标题从“DAO实现方法中一个Connection捅到底好吗?头疼”改成“细粒度处理事务,尽快的结束事务”,这个是我最终的目的。现在我明白了整 个业务方法调用过程中都是使用同一个SESSION(Connection)。至于业务逻辑怎样来平衡分布,是不是可以把一部分放到ACTION,一部分放到service,Dao只负责和数据库处理。对只读的事务我对其只用readOnly。

比如:我上面的例子是不是可以变成如下的样子呢?

//对应表的相关操作
public interface DAO{
     public List get##(String s);
     public void update##(String ...);
     public void delete##(String ...);
     public void insert##(String ...);
     public List find##(String...);

}


public class Service{
    public DAO dao = .......;//注入DAO对象。

    //结合DAO执行相应的业务处理操作
    //该方法上加事务,传播途径为required
    public void update###(){
          
           dao.update##(String ...);
           dao.delete##(String ...);
           dao.insert##(String ...);

           //处理更复杂的业务逻辑。
           logice();
   } 
 
   
   //该方法上加事务,传播途径为required,readOnly
   public  String get###(String s){
          return dao.get(s);
   }

  
   //该方法上加事务,传播途径为required,readOnly
   public List find###(String...){
          return dao.find##(String...);
   }

    public void logice(){  
          //to do something  
  } 
   
}

/**
*那么action中是不是可以变成如下的样子呢?
*
*/
public class Action{
     //注入服务类
     public Service service = null;
     public ActoinForward update###(ActionForm...............){
           //下面这样调用是不是会能更好的呢?
            service. get###(s);
            service. update###();
            service. find###(String...);
    }
}

   我们希望能够更快的结束事务,避免不必要的阻塞,保证系统有更好的性能。

 

 

 

分享到:
评论
20 楼 fangwei 2008-11-11  
风花雪月饼 写道

真会这么高效么?
声明事务覆盖的方法中如果只有一个数据库操作我觉得有没有事务都一样的。
从Spring的文档上看,似乎不是很推荐手动控制,说这样就造成了入侵性还是什么。但是说也有特殊情况。
其实我也整不明白,为什么就一个insert的方法也得声明事务。这不是找茬么。。。比如save(Entity entity)里面很简单的最终调用了HibernateTemplate.save。也是事务。


同意,一个insert的方法确实不需要声明事务。
19 楼 风花雪月饼 2008-10-29  
sdh5724 写道
我说的是大规模的并发环境下意见, 每天有千万以上PV的站点:
1.绝对禁止使用声明式事务
2.小心手动控制事务处理, 处理好数据准备工作, 尽量把事务在最小的代码块里完成.

这么说吧, 大规模并发环境中, 使用手动事务比声明式事物性能高3-5倍<通过长期观察得出的结论>. 而且声明事物容易发生死锁行为.
最终的解决方案, 对于基于服务的应用. 自己做事务服务器. 我知道有站点这么作的. 我目前也在做哈, 不然SOA类型的应用, 想控制事务太困难.  哈.


真会这么高效么?
声明事务覆盖的方法中如果只有一个数据库操作我觉得有没有事务都一样的。
从Spring的文档上看,似乎不是很推荐手动控制,说这样就造成了入侵性还是什么。但是说也有特殊情况。
其实我也整不明白,为什么就一个insert的方法也得声明事务。这不是找茬么。。。比如save(Entity entity)里面很简单的最终调用了HibernateTemplate.save。也是事务。
18 楼 sdh5724 2008-10-29  
我说的是大规模的并发环境下意见, 每天有千万以上PV的站点:
1.绝对禁止使用声明式事务
2.小心手动控制事务处理, 处理好数据准备工作, 尽量把事务在最小的代码块里完成.

这么说吧, 大规模并发环境中, 使用手动事务比声明式事物性能高3-5倍<通过长期观察得出的结论>. 而且声明事物容易发生死锁行为.
最终的解决方案, 对于基于服务的应用. 自己做事务服务器. 我知道有站点这么作的. 我目前也在做哈, 不然SOA类型的应用, 想控制事务太困难.  哈.

17 楼 fangwei 2008-10-27  
在我曾经做过的系统中遇到过与楼主同样的问题,我既希望在操作失败时能回滚数据库,但又不希望长时间锁住一个表(这里在并发多时会出现性能问题,也就是楼主说的阻塞)。

1.首先也是想到了将原本在1个service中的多个dao分解到不同的service中,然后在action中调用多个service(我们也是将事务声明在了service层)。这样做使用了多个数据库连接,的确能在一定程度上避免阻塞,但在一个会话中创建多个数据库连接是比较耗费资源的(使用连接池可能会好一点),更重要的是事务也不好控制。比如你的dao顺序是:
select
update
select
delete
select。

2.因为在spring框架中没有找到更好的事务配置办法,后来采用了硬编码处理sql异常来控制事务。上面的多个dao还是放在1个service中,取得连接并将使用其默认的自动提交属性设置true(即执行完一个dao就提交),分别处理各个dao抛出的异常,执行相应的dao以保持数据的一致性(相当于回滚数据库)。这样做使得锁住一个表的时间缩短从而降低了阻塞发生的几率,而且只创建1个数据库连接降低了资源耗费,缺点是编码太过繁琐,例如update还得保存之前的值用以回滚。

最后权衡了一下系统的实际情况,系统在内网使用,数据库在局域网,在一次会话过程中发生数据库异常的可能性非常小,所以,像这种情况的service,我选择了性能,放弃了事务。不知道大侠们都是如何处理这种service的?
16 楼 kyo100900 2008-10-14  
hgq0011 写道
daquan198163 写道
而且通常需要用opensessioninview filter(你们也用了吧),

  我们没有用它,也是考虑到一个请求处理有时会占用很长的时间所以没有用它。

因为系统在某些时间段并发量大,业务有比较复杂,所以要优化程序优化SQL,具体有什么好的建议吗?谢谢



如果并发量大,业务复杂(可能是一个长事务)的话,hibernate提供的乐观锁机制可以一定程度上缓解数据库的压力。
15 楼 cuiyi.crazy 2008-10-13  
<div class='quote_title'>hgq0011 写道</div>
<div class='quote_div'>
<p>      在搭建系统的架构时我们采用了ssh+ajax等方式构建的。我一在和大家说我们要层次分明,思路清晰,可现在都比较糟糕。</p>
<p>       比如:JSP页面用来显示数据的,css用来美化页面
&lt;script src="/javascripts/tinymce/themes/advanced/langs/zh.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="/javascripts/tinymce/plugins/javaeye/langs/zh.js" type="text/javascript"&gt;&lt;/script&gt;
,JS用来控制页面的。现在很多页面中什么都有了,臭味很多。</p>
<p>       在后台我们也分了action,service,dao层,原本action用来控制调度的,service用来处理相关的业务逻辑的,DAO中用来CRUD数据的。可现在出现了action包裹着一部分逻辑,service就非常简单了,就是用来调用DAO中的方法,而DAO中的方法即包裹了业务处理逻辑又包裹了CRUD数据处理。而且有的业务逻辑非常的复杂,涉及到的表操作很多</p>
</div>
<p>action要做到delegate到service,也要fill到view中,包含部分逻辑也是合理的。</p>
<p>dao方法中包含部分业务逻辑也是合理的,这个是充血domian object的做法,hibernate也支持的很好,也不是不合理的...</p>
<p> </p>
<p>楼主用的dao和hiberante orm持久对象应该是贫血模型吧?</p>
14 楼 cuiyi.crazy 2008-10-13  
hgq0011 写道
daquan198163 写道
由于事务的边界在service层,所以action只能调用service一次,这样才能保证业务逻辑全在同一事务内

是的。我的想法是把那些只是查询的放在一个SERVICE方法中(事务传播为readOnly),,把那些对数据有更新的动作放在另外一个方法中(事务传播为required)的。这样就不会对整个业务方法都是required了,这样是不是会要好些呢?

spring提供的namematch的事务方法,很支持这个做法的
13 楼 ThinkingInAll 2008-10-13  
我是这样做

我执行service后,跳到另一个action执行readonly的service
这样就不冲突了

没有必要执行service后还要帮后面一个页面查询数据,可以交给另一个action查数据
12 楼 hgq0011 2008-10-11  
daquan198163 写道
由于事务的边界在service层,所以action只能调用service一次,这样才能保证业务逻辑全在同一事务内

是的。我的想法是把那些只是查询的放在一个SERVICE方法中(事务传播为readOnly),,把那些对数据有更新的动作放在另外一个方法中(事务传播为required)的。这样就不会对整个业务方法都是required了,这样是不是会要好些呢?

daquan198163 写道

service层业务处理很少会成为瓶颈,无非是一些增删改查
一般不需要做什么优化,因为hibernate的session缓存、延迟加载本身就很高效了,都是默认配置
个别的查询可能会成为瓶颈,

因为有时并发量大,每个业务操作的关联的表很多。事务这块还是要注意的吧

daquan198163 写道

可以利用p6spy+sqlprofile提供的索引建议来调优

谢谢,我也用它们监控我的SQL。

11 楼 daquan198163 2008-10-10  
由于事务的边界在service层,所以action只能调用service一次,这样才能保证业务逻辑全在同一事务内
service层业务处理很少会成为瓶颈,无非是一些增删改查
一般不需要做什么优化,因为hibernate的session缓存、延迟加载本身就很高效了,都是默认配置
个别的查询可能会成为瓶颈,可以利用p6spy+sqlprofile提供的索引建议来调优
10 楼 hgq0011 2008-10-10  
daquan198163 写道
而且通常需要用opensessioninview filter(你们也用了吧),

  我们没有用它,也是考虑到一个请求处理有时会占用很长的时间所以没有用它。

因为系统在某些时间段并发量大,业务有比较复杂,所以要优化程序优化SQL,具体有什么好的建议吗?谢谢
9 楼 hgq0011 2008-10-10  
daquan198163 写道
session是绑定到ThreadLocal的,你再怎么分层也是一样的

恩了,
那么象比较负责的业务处理通常你们是怎么做的呢?

事务尽快尽早的结束,也就是优化程序,优化SQL。那么具体怎么优化呢?
8 楼 daquan198163 2008-10-10  
对的,事务发起后,session是绑定到ThreadLocal的,所以……

而且通常需要用opensessioninview filter(你们也用了吧),所以即便你action里分多次调用service,也还是用的同一个session,占用资源的时间只会更长,而且这样调用service会导致事务不一致
7 楼 hgq0011 2008-10-10  
laiseeme 写道
你用了hibernate然后又调用jdbc处理...

有些简单的处理用HIbernate来处理就可以了,但复杂的查询用JDBC来处理会比较好点,也比较好控制。
6 楼 laiseeme 2008-10-09  
你用了hibernate然后又调用jdbc处理...
5 楼 hgq0011 2008-10-09  
http://www.iteye.com/topic/87426?page=1看了这篇我明白了--我用的两种方法其实都用的是同一个session(Connection).
4 楼 hgq0011 2008-10-08  
taopian 写道

     把Service层做厚,确实要花费不少时间,想想SOA的概念,这个是一个代码结构逐渐调整的概念。


我现在的工作是检查其他同学写的代码,找出代码中有臭味的地方,优化这个系统。其实,这工作很痛苦。希望大家给我优化系统更好的建议。谢谢!
3 楼 hgq0011 2008-10-08  
chhj_292 写道

感觉你是在为了分层而分层。

# public List update###(){ 
#            dao.get(s); 
#            dao.update##(String ...); 
#            dao.delete##(String ...); 
#            dao.insert##(String ...); 
#            return dao.find##(String...);
//处理更复杂的业务逻辑。
#    }  

public void logice(){
  //to do something
}

这段代码,不知道你怎么保证会在一个事务里完成。


当然了“public List update###()”这个方法中还有其它的业务处理逻辑,或者会在sevice类中定义相关的方法吧。

我用SPRING的声明事务,对SERVICE层进行事务拦截。


顺便说一下:我刚才仔细的看了without EJB关于事务的那张。明确了我一个模糊的概念,就是SPRING的声明事务会对所调用业务方法进行拦截,也就是对它调用的DAO方法处在同一个事务中。
2 楼 taopian 2008-10-08  
个人觉得,这个是蛮常见的现象,在做Web层代码的时候(就是你这里所说的action),很容易会把业务逻辑相关的代码都完成了。原因其实很简单,因为把Web交互的代码和业务逻辑代码混淆了。

把Service层做厚,确实要花费不少时间,想想SOA的概念,这个是一个代码结构逐渐调整的概念。

再来看一下DAO层,会发现你的Service层的薄,DAO层也是罪魁祸首之一。应该把事务控制在Service层,而不是在DAO层。

DAO层提供的接口,应该是简单的数据操作接口,而不应该包含复杂的业务逻辑在里面。
1 楼 chhj_292 2008-10-08  
你既然选择了这样一种分离的模式,DAO中就不应该包含过多的业务逻辑,甚至不应该包含任何业务逻辑只关心(Data Access)。特别是不应该为了你自己模块的实用性,而抛弃整个借口的适用性,那样,分层的意义也就没有了。
感觉你是在为了分层而分层。

# public List update###(){ 
#            dao.get(s); 
#            dao.update##(String ...); 
#            dao.delete##(String ...); 
#            dao.insert##(String ...); 
#            return dao.find##(String...); 
#    }  

这段代码,不知道你怎么保证会在一个事务里完成。

相关推荐

Global site tag (gtag.js) - Google Analytics