我来也! 请教一下,在纯的JDBC中,如何项目采用分层了DAO层,服务层和SERVLET控制层,,那么怎么在servlet中启用JDBC的事务?

立志做一个佳娃~ 2008-07-05 06:18:10
我来也! 请教一下,在纯的JDBC中,如何项目采用分层了DAO层,服务层和SERVLET控制层,,那么怎么在servlet中启用JDBC的事务?
...全文
1229 43 打赏 收藏 转发到动态 举报
写回复
用AI写文章
43 条回复
切换为时间正序
请发表友善的回复…
发表回复
vivazhao 2009-08-01
  • 打赏
  • 举报
回复
我觉得事务的界限不应该是dao层,应该是逻辑层毕竟已个逻辑可能用到多个dao方法。而事务的控制的话,就是传递connection,可以将connection放在ThreadLocal中,这样就可以不用手动的传递了
Wuaner 2009-07-30
  • 打赏
  • 举报
回复
mark 啦
y_linspace2 2009-07-30
  • 打赏
  • 举报
回复
好贴,学习~
yulin_aijia 2008-11-05
  • 打赏
  • 举报
回复
分层的时候 总是发现逻辑都乱掉了 不太清楚各层之间是如何联系到一起的
好象所有的东西到最后又都搅到一块去 了 着急啊
silence1214 2008-10-06
  • 打赏
  • 举报
回复
添加一个service层 然后事务坐在 service层
controller调用service
service中为 dao的某个或者某几个方法的组合

如果不用spring 那么就用filter来实现
  • 打赏
  • 举报
回复
说实在的,我认为这个帖子的题目和出发点很好,建议加精,能让更多的人进来
讨论一下。

想想大家大多数都用 Struts + Spring + Hibernate 吧,事务处理往 Spring
的配置中一加好,就万事大吉了。估计很少有人会去研究为什么代码中一个
Connection 代码都看不到,而同样有着各种方式的事务管理呢?

这个帖子的标题,用到的技术是底层的 Servlet + JDBC 与任何框架没有依赖
关系,从最底层自行实现事务管理,呵呵,难度应该不小,如果完成的话,那
就会惊叹 Spring 中的事务管理模块的处理方式。

看看楼上的回复,大多数都建议在业务层中处理事务,但是我突然想到个问题。
下面是业务层中的方法:

public void a() {
con.setAutoCommit;
dao.a();
b(); // 调用 b 方法
dao.a();
con.commit;
}

public void b() {
con.setAutoCommit;
dao.b();
dao.b();
con.commit;
}

public void c() {
con.setAutoCommit;
dao.c();
dao.c();
con.commit;
}


注明一下,con.begin 和 con.commit 是通过动态代理实现的,并不是每个方法中手工加上去的。

在 Servlet 中调用:

service.a();
service.c();

这样的话,a c 根本不能处理同一事务控制下,因为事务的边界在 Servlet 层,
并不在 Service 层中。所以在 Service 层中写事务控制语句是不对的,应该再
更高一层,Servlet 层,或者再建一个 Facade 层,把这些方法写到 Facade 层
中的一个方法中,在这个方法里处理事务。

但是弄个 Facade 这样的话我们又会碰到事务的传播性这个问题,比如下面的代码:

public void facade1() {
con.begin
service.a();
service.b();
facade2(); // 调用 facade2 方法
con.commit;
}

public void facade2() {
con.begin
service.e();
service.f();
con.commit;
}


在 facade1 中调用了 facade2 方法,注意在 facade2 中本身有事务,这时再将其
纳入了 facade1 中的事务,但根据事务的概念,facade2 在纳入 facade1 中,如果
facade1 中有事务,就加入 facade1 中的事务,自己的事务就取消了,如果没有的
话,就打开自己的事务处理,这个就是事务传播性问题。

如果要从 AOP 切入事务处理的话,事务传播性是必须考虑到的问题,PS 一下,Spring
就是这么做的。

如果那样做的话,事务处理模块将会变得复杂,但是这样也有好处,那就是是不依赖
于框架、平台和架构,能在 Web 程序或者是 Swing 程序中使用。

当然了,如果是专门针对于 Web 的事务管理,就不要那么复杂了,直接在 Filter
中进行事务处理,每个请求,服务器都开启一个线程,这样我们就可以在线程中绑定
Connection,在 DAO 中从当前线程中获得 Connection,在 Filter 中处理事务,在
JDK 中正好提供了 ThreadLocal 这样一个类,可以在当前的线程中绑定对象,呵呵。

上面是我对这个帖子事务处理的一些看法,仅仅是凭空想象的,还没实践过,在这里
仅仅作为讨论,希望大家都能参与一下。

胡矣 2008-07-08
  • 打赏
  • 举报
回复
不要在servlet中
servlet一般都是做控制层的
放到逻辑层(javabean)中
fulianglove 2008-07-08
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 bao110908 的回复:]
否则每个 Servlet 中都得嵌入这些事务处理语句了,感觉不好。
[/Quote]
应用模板模式,将事务的处理放在父类中,该父类先继承httpservlet,所有的servlet都可继承这个父类
  • 打赏
  • 举报
回复
你好哈,不要叫我前辈哦,我不是什么前辈哦 :)

我也没实践做过,试试看吧,只作为讨论,也不知道有没有实际用处,呵呵

就是把 30 楼的第一段代码搬到 Filter 中来

doFilter

Connection con = null;
ConnectionManager manager = ConnectionManager.getInstance();
try {
con = manager.getConnection();
con.setAutoCommit(false);
chain.doFilter(request, response);
con.commit;
}catch(Exception e) {
con.rollback;
}finally{
if(con!=null) {
con.close();
}
manager.removeConnection();
}
  • 打赏
  • 举报
回复
请教逝月和火龙果前辈

如果用过滤器,我对这个办法比较有兴趣,希望指教,感谢
tianshangui 2008-07-07
  • 打赏
  • 举报
回复
随便看看.
  • 打赏
  • 举报
回复
否则每个 Servlet 中都得嵌入这些事务处理语句了,感觉不好。
  • 打赏
  • 举报
回复
嗯,看样子只能将事务处理放在过滤器中实现了。
jianpc 2008-07-07
  • 打赏
  • 举报
回复
可以用过滤器啊,将事务控制范围扩展至一次请求。
  • 打赏
  • 举报
回复
调用多个方法,如果是这样的话,在 Servlet 中只能侵入 Connection 对象了,否则可以采用低侵入式的。

下面是 Servlet 中进行修改的部分:

Connection con = null;
ConnectionManager manager = ConnectionManager.getInstance();
try {
con = manager.getConnection();
con.setAutoCommit(false);
service1.s1();
service2.s2();
service3.s3();
con.commit;
}catch(Exception e) {
con.rollback;
}finally{
if(con!=null) {
con.close();
}
manager.removeConnection();
}


ConnectionManager 采用 ThreadLocal<Connection> 对象作为 Connection 的存储容器。
getConnection() 中的大致代码(仅供参考,手工写的,没有测试过):

public ConnectionManager {
private static ThreadLocal<Connection> cons = new ThreadLocal<Connection>();
private static ConnectionManger manger = new ConnectionManager();

private ConnectionManger() {
}

// 不使用单例的话,把下面的这些方法改成静态的也行
public static ConnectionManager getInstance() {
return manager;
}

public Connection getConnection() throws SQLException {
Connection con = cons.get();
if(con == null) {
// 从 ConnectionFactory 中获得一个连接
con = ConnectionFactory.getConnection();
setConnection(con);
}
return con;
}

public void removeConnection() {
cons.remove();
}

private void setConnection(Connection con) {
cons.set(con);
}
}


Service 层的代码可以不用动了。

DAO 的代码得进行重构:

1,Connection 从 ConnectionManager 的 getConnection 中获得;
2,DAO 层中的 con.close 得全部去掉,就是不关,因为关掉的话,一个事务点就中止了;
3,DAO 层中的凡是抛出 SQLException 的地方在 catch 块中,重新包装一个自定义的 RuntimeException
再进行抛出,因为事务层放到了 Servlet 中,这里必须把异常抛出,否则在高层就没办法判断是运行正常还是
产生异常了。之所以使用 RuntimeException 主要是考虑到 service 层中不用再去修改了,如果是直接抛出
SQLException 的话,由于它是检查型异常必须处理的,这样得在 service 的每个方法后都 throws SQLException
这样的话,有点太烦了,也不是很好。

DAO 重构后的代码基本上如下面这样:

Connection con = null;
PreparedStatement ps = null;
try {
con = ConnectionManager.getConnection();
ps = con.prepared....;
ps.execute(....);
}catch(SQLException e) {
throw new WrapperSQLException(e);
}finally {
if(ps != null) {
try {
ps.close();
}catch(SQLException e) {
throw new WrapperSQLException(e);
}
}
// 这里的 con 不能关
}


由于使用的 ThreadLocal 来存储 Connection,每个请求是独立的线程 ThreadLocal 中也只有一个 Connection
使用这个就可以将 Connection 进行传递了,而无需将 Connection 当作参数一层一层地传递下去了。

另外,使用了 ThreadLocal,也不会产生线程安全的问题。

如果,你的 Servlet 中完成一个业务,只是调用一个业务层的方法的话,那就更加方便了,Servlet 中的那段代码
只要使用动态代理将其切入到业务层对象中,直接调用业务类的代理对象就行了,这样就不需要让 Connection 侵入
代码中了。

当然了,调用多个业务方法,采用代理进行处理的话会很麻烦,因为多个方法必须纳入到一个事务中的去,涉及事务的
传播属性,一般采用方法栈的方式进行处理,这得考虑很多的问题,类的结构需要精心设计。
Sou2012 2008-07-07
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 poscard 的回复:]
应该是服务层调用dao层,服务层控制事务。
如果只是传Connection的话,也算不上耦合。
[/Quote]
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 Andy_Fay 的回复:]
绝对应该在服务层。。。。
事务是以业务逻辑为基础的
一个完整的业务应该对应服务层里的一个方法
如果业务操作失败,则整个事务失败。

DAO层应该保证操作的原子性,就是说DAO里的每个方法都应该是不可以分割的。所以事务是肯定没有必要加在DAO这一层的

同样,对于Servlet,每一次请求对应的可能不止一个业务,打个比方,做一个删除请求,删除成功了之后肯定还要返回显示列表吧,那么这一次请求应该包含两个独立的业…
[/Quote]


感谢你的回答,很有见解,

----
同样,对于Servlet,每一次请求对应的可能不止一个业务,打个比方,做一个删除请求,删除成功了之后肯定还要返回显示列表吧,那么这一次请求应该包含两个独立的业…
----

这个例子举的比较牵强,,,

如果是删除一个主贴呢,,那么跟 贴是必须要删除的,,

也就是说,SERVLET中的所有的操作是一个整体,,,,

另外Service层有可能一个业务功能需要调用N个方法,这种情况怎么办??

这N个方法是一个整体,,,
palm_civet 2008-07-06
  • 打赏
  • 举报
回复
jdbc有事务控制,一旦发生上面错误向外抛异常(不提交事物),servlet捕捉异常,根据不同的异常转到不同的页面
小五五 2008-07-06
  • 打赏
  • 举报
回复
绝对应该在服务层。。。。
事务是以业务逻辑为基础的
一个完整的业务应该对应服务层里的一个方法
如果业务操作失败,则整个事务失败。

DAO层应该保证操作的原子性,就是说DAO里的每个方法都应该是不可以分割的。所以事务是肯定没有必要加在DAO这一层的

同样,对于Servlet,每一次请求对应的可能不止一个业务,打个比方,做一个删除请求,删除成功了之后肯定还要返回显示列表吧,那么这一次请求应该包含两个独立的业务逻辑。那么是不是说本来删除成功了,但在查询显示列表的时候出现在异常,就把删除的操作也回滚呢?
qinqinhao 2008-07-06
  • 打赏
  • 举报
回复
ding
ding
加载更多回复(22)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧