新足迹

 找回密码
 注册

精华好帖回顾

· 说说我溜猫的经历.-照片已经上了 (2009-4-6) suel · 让我们共同追忆逝去的青春系列之一 - 张雨生 (2009-12-7) Melbourner1978
· 澳网女单第二轮 李娜对瑞士选手Berlinda Bencic (2014-1-15) astina · 回复”儿子的一些经验教训“一帖,谈谈我对孩子阅读、兴趣班、成功等的一些看法 (2014-1-30) JuliaTung
Advertisement
Advertisement
查看: 3647|回复: 45

IT民工问问题: JPA/Hibernate 如何确保多个访问用同一个connection [复制链接]

发表于 2010-9-16 11:47 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
这是中途接手的一个项目, 最近发现个问题, google无果, 这里问问看.

系统框架: Spring Framework, JPA + Hibernate, MVC是struts. Module 类就是POJO, 用annotation做O/R mapping. DAO里面有EntityManager实例, 用来load和persist module object. 通过Spring inject DAO 到 Struts Action里.

功能需求: 页面更改学生成绩, 后台先更新grade和mark, 然后call一个Oracle procedure, procedure里run几个batch, 确定并更新这个学生的状态(grad/exclude/enrol ...)

Issue: 更改学生成绩是通过 DAO 类, 不用(也没法)操作connection对象, 直接entityManager.persist(), so far so good. 然后要call Oracle procedure, 但是没法通过entityManager (JPA没有相关API), 只能从datasource里面拿个connection出来(JNDI lookup), 问题在于, 这个JNDI拿到的connection和上面DAO用到的connection(EntityManager控制)不是同一个, 所以DAO刚刚保存的数据在call Oracle procedure这个connection里不可见!

我试了写一个Oracle function, 然后通过entityManager.createNativeQuery()来call这个function, 结果发现问题依旧, DAO保存的状态在这个function里不可见!

我试过Spring的Transaction, PlatformTransactionManager这个class, 但是也没有帮助.

问题今天已经想办法绕过去了, 但是也许下次就绕不过去了哪? 达人给讲讲吧. 如果哪里说的不清楚, 我一定解答.
Advertisement
Advertisement

发表于 2010-9-16 11:53 |显示全部楼层
此文章由 北风 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 北风 所有!转贴必须注明作者、出处和本声明,并保持内容完整
不懂java
不能先把DAO的改动的数据先commit进数据库?

发表于 2010-9-16 11:54 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
不能先把DAO的改动的数据先commit进数据库?

不行呀, 万一后面的procedure出了问题, 就没法rollback了
而且吧... 我还真不知道JPA/Hibernate怎么强制commit

发表于 2010-9-16 12:31 |显示全部楼层
此文章由 乱码 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 乱码 所有!转贴必须注明作者、出处和本声明,并保持内容完整
我也不懂java,但从.net这些tools来看,过于依赖entityManager作persist不是个好主意。store procedure一直是我们的首选.

在.net这边,entity framework原来支持sp不够好,现在据说支持的还可以。我们原来用它主要是生成entity class,不用手工建了,但跟db persist,还是用ado.net的那些东西,而不是entity manager,如果真的要用,要特别注意到db的traffic,可能有相当一部分是你不想要的。

作tran commit/rollback的确需要同一个connection.

评分

参与人数 1积分 +3 收起 理由
zn7726 + 3 握手

查看全部评分

2010年度奖章获得者

发表于 2010-9-16 12:32 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
愛惜生命, 遠離open source

发表于 2010-9-16 12:38 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
难道各位商用系统没有用O/R mapping的? 上了这条船, 就只能把connection, transaction这类东西交给framework管理了, 还不是很熟悉他们的API, 没底呀.
Advertisement
Advertisement

2010年度奖章获得者

发表于 2010-9-16 12:41 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
ORM 當然支持 inject connection, transaction.

发表于 2010-9-16 12:45 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
ORM 當然支持 inject connection, transaction.

没说不支持呀, 但是不是很灵活吧. 比如我遇到的这个问题, 就不知道怎么办了. dalaohu帮忙给指点一下.

2010年度奖章获得者

发表于 2010-9-16 12:45 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
ORM 裡內置的connection 你全部可以 inject 進去, 你連connection都控制了,當然能控制transaction.

发表于 2010-9-16 12:51 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
ORM 裡內置的connection 你全部可以 inject 進去, 你連connection都控制了,當然能控制transaction.

有道理, 您给深入说说行吗.

发表于 2010-9-16 12:52 |显示全部楼层
此文章由 cdfei 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 cdfei 所有!转贴必须注明作者、出处和本声明,并保持内容完整
ado.enitty的connection是可以inject进去的,ObjectContext的构造函数有个一个,
public MySqlEntities(EntityConnection connection) : base(connection, ContainerName)
你可以创建了connection注入,另外它也暴露了当前Connection实例,你可以随时直接使用。你看看你用的框架有没有类似的。
Advertisement
Advertisement

2010年度奖章获得者

发表于 2010-9-16 13:03 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
一般ORM都會自動rollback transaction.

你也可以手動。

using (TransactionScope ts = new TransactionScope())
{
    //commit to db
    ts.Commit();
}

有些orm 你要explicitly call entityManager.Connection.BeginTransaction()

不太明白你為什麼要把connection, 取出來,在放到別的地方去?

再具體,我得上門看code了 :)
足迹 Reader is phenomenal. If you never used, you never lived 火速下载

发表于 2010-9-16 13:28 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
dalaohu你说的transaction控制, 我测试过, 没用.
这里的问题在于, 先用DAO(通过entityManager) 保存entity, 然后需要一个connection来call oracle procedure. 保存好entity后, entitymanager似乎没有commit, 所以最新的状态在oracle procedure里不可见, 因为后面用到的connection和前面entityManager用的不是一个. 所以希望保存entity和call procedure用同一个connection对象. 但是貌似做不到.

2010年度奖章获得者

发表于 2010-9-16 13:35 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
原帖由 zn7726 于 2010-9-16 13:28 发表
因为后面用到的connection和前面entityManager用的不是一个. 所以希望保存entity和call procedure用同一个connection对象


不明白,connection string是放在global config 裡的,

你既然“前一個” 用了這個connection, 為什麼不在 “後一個” instaniate是也用呢?

“前一個” 和 “後一個” 都應該從 config 裡拿connection, 而去是從“前一個” 裡拿。
足迹 Reader is phenomenal. If you never used, you never lived 火速下载

发表于 2010-9-16 13:42 |显示全部楼层
此文章由 北风 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 北风 所有!转贴必须注明作者、出处和本声明,并保持内容完整
前后两次使用,即使connection string用一样的,也不是一个PID了吧
所以没commit的东西是不会被发现的
还是得要先commit

或者把你要在sp里面要实现的功能,放到code里面去?
If you let people believe that you are weak, sooner or later you’re going to have to kill them.

发表于 2010-9-16 13:51 |显示全部楼层
此文章由 cdfei 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 cdfei 所有!转贴必须注明作者、出处和本声明,并保持内容完整
connection实例和connection  string没啥关系,会到connection pool立马再拿一个来
Advertisement
Advertisement

2010年度奖章获得者

发表于 2010-9-16 13:52 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
原帖由 zn7726 于 2010-9-16 13:28 发表
dalaohu你说的transaction控制, 我测试过, 没用.
这里的问题在于, 先用DAO(通过entityManager) 保存entity, 然后需要一个connection来call oracle procedure. 保存好entity后, entitymanager似乎没有commit, 所以最 ...


我好像領悟到你說的意思了。

你有2個db, 每個db各有一個 “EntityManager”.

你想從一個EntityManger, 寫數據到另一個db。

首先這麼做是不對的, 就讓每個EntityManager 只管自己的db 是最好的。絕對不要有cross-over
足迹 Reader is phenomenal. If you never used, you never lived 火速下载

发表于 2010-9-16 14:02 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
dalaohu你领会错了

就一个DB, 一个EntityManager. 只不过是两步数据库访问, 第一步通过DAO(EntityManager) 保存POJO, 第二步call oracle procedure. 由于EntityManager的参与, 不能保证一个connection从头用到尾, 所以第一步的结果第二步看不到.

发表于 2010-9-16 14:11 |显示全部楼层
此文章由 kawara 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 kawara 所有!转贴必须注明作者、出处和本声明,并保持内容完整
call entitymanaer.flush()  immediately after entityManager.persist()

then entityManager.createNativeQuery()

Hopefully it works.

Hibernate doesn't  maintain a constant connection during transaction.It only use one when "absolutely necessary"

发表于 2010-9-16 14:18 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
call entitymanaer.flush()  immediately after entityManager.persist()

then entityManager.createNativeQuery()

Hopefully it works.


transaction 怎么保证呀? 后面call Oracle procedure应该是被看作transaction的一部分.

另外, 在页面上可能会输入很多学生的mark/grade信息, 后台肯定是loop, call DAO来一个个保存. 我总不能在每个DAO的save method里都强制flush吧.

不知道如果强制flush了(commit了), 并且把这一段全放在transaction里, 出了异常还能不能rollback.

唉, 怀念JDBC呀...

发表于 2010-9-16 14:22 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
前后两次使用,即使connection string用一样的,也不是一个PID了吧
所以没commit的东西是不会被发现的
还是得要先commit

对. DataSource是基于string的, 但实际上说的connection对象并不是真的JDBC连接, 都是pool的, 线程池的概念, 每次拿到的不一样.

或者把你要在sp里面要实现的功能,放到code里面去?

考虑过这个办法(最安全最保险), 不过那个SP有1000行+
Advertisement
Advertisement

发表于 2010-9-16 14:22 |显示全部楼层
此文章由 kawara 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 kawara 所有!转贴必须注明作者、出处和本声明,并保持内容完整
Flush is not commit.

It just save changes into datastore.later you can still ask datastore to commit or rollback.

[ 本帖最后由 kawara 于 2010-9-16 14:26 编辑 ]

发表于 2010-9-16 14:29 |显示全部楼层
此文章由 kawara 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 kawara 所有!转贴必须注明作者、出处和本声明,并保持内容完整
原帖由 北风 于 2010-9-16 13:42 发表
前后两次使用,即使connection string用一样的,也不是一个PID了吧
所以没commit的东西是不会被发现的
还是得要先commit

或者把你要在sp里面要实现的功能,放到code里面去? ...

uncommitted changes cannot be seen from different transitiosn under isolation level above READ_UNCOMMITTED, However still can be seen in the same transaction

发表于 2010-9-16 14:31 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
Flush is not commit.

It just save changes into datastore.later you can still ask datastore to commit or rollback.

谢谢.
如果不是commit, 估计没戏. 有办法强制commit吗?

2010年度奖章获得者

发表于 2010-9-16 14:49 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
那我就只剩殺手鐧了。

你直接commit把, 別transaction了。

发表于 2010-9-16 14:50 |显示全部楼层
此文章由 kawara 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 kawara 所有!转贴必须注明作者、出处和本声明,并保持内容完整
原帖由 zn7726 于 2010-9-16 14:31 发表

谢谢.
如果不是commit, 估计没戏. 有办法强制commit吗?

I don't know any way to force commit in Spring managed transaction.

I don't understand why you want commit it?For your store procedure to see your changes you don't need commit it,just flush it into database.
Advertisement
Advertisement

发表于 2010-9-16 14:51 |显示全部楼层
此文章由 zn7726 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 zn7726 所有!转贴必须注明作者、出处和本声明,并保持内容完整
For your store procedure to see your changes you don't need commit it,just flush it into database.

好, 我试试看.

2010年度奖章获得者

发表于 2010-9-16 14:53 |显示全部楼层
此文章由 dalaohu 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 dalaohu 所有!转贴必须注明作者、出处和本声明,并保持内容完整
再問個傻問題。

既然你走entity framework路線, 為啥要直接call proc?

发表于 2010-9-16 14:53 |显示全部楼层
此文章由 北风 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 北风 所有!转贴必须注明作者、出处和本声明,并保持内容完整
他说了,sp和前面那些不是一个transaction

原帖由 kawara 于 16/9/2010 14:50 发表

I don't know any way to force commit in Spring managed transaction.

I don't understand why you want commit it?For your store procedure to see your changes you don't need commit it,just flush it into ...
If you let people believe that you are weak, sooner or later you’re going to have to kill them.

发表于 2010-9-16 14:56 |显示全部楼层
此文章由 kawara 原创或转贴,不代表本站立场和观点,版权归 oursteps.com.au 和作者 kawara 所有!转贴必须注明作者、出处和本声明,并保持内容完整
原帖由 北风 于 2010-9-16 14:53 发表
他说了,sp和前面那些不是一个transaction


When?

发表回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Advertisement
Advertisement
返回顶部