- 浏览: 86473 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
shu_jian:
太深奥了,看不太懂啊
声明式事务管理 -
hengstart:
谢谢了!在你这里看了不少东西,交个朋友,我也在上海java的! ...
mysql有种类型不支持事物 -
hengstart:
看不出来结果啊!什么都没有!
mysql有种类型不支持事物 -
whg333:
拉登的足球 写道最简单的方式
看的时机: 在人物的脚转到最左 ...
一张图分出你是用左脑还是右脑! -
whg333:
Jason(aijun) 写道
唯心主义者应该非常喜欢这 ...
一张图分出你是用左脑还是右脑!
目的:使用HibernateTemplate执行execute(new HibernateCallback())方法,从HibernateCallback中得到session,在此session中做多个操作,并希望这些操作位于同一个事务中。
如果你这样写(1):
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();//实际上,如果不是程序员"手痒"来调用这个flush(),HibernateTemplate中session的事务处理还是很方便的
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
}
});
} 你期望spring在执行完execute回调后,在关闭session的时候提交事务,想法是很好的,但spring并不会这么做.让我们来看看在Hibernate的源代码中,session.beginTransation()做了什么事。看如下代码(2):
public Transaction beginTransaction() throws HibernateException {
errorIfClosed();
if ( rootSession != null ) {
// todo : should seriously consider not allowing a txn to begin from a child session
// can always route the request to the root session
log.warn( "Transaction started on non-root session" );
}
Transaction result = getTransaction();
result.begin();
return result;
}这个方法中的result是一个org.hibernate.transaction.JDBCTransaction实例,而方法中的getTransaction()方法源代码为(3):
public Transaction getTransaction() throws HibernateException {
if (hibernateTransaction==null) {
log.error(owner.getFactory().getSettings()
.getTransactionFactory().getClass());
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory()
.createTransaction( this, owner );
}
return hibernateTransaction;
}再次追踪,owner.getFactory().getSettings() .getTransactionFactory()的createTransaction()方法源代码如下(4):
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
throws HibernateException {
return new JDBCTransaction( jdbcContext, transactionContext );
}它返回了一个JDBCTransaction,没什么特别的。
在代码2中,执行了result.begin(),其实也就是JDBCTransaction实例的begin()方法,来看看(5):
public void begin() throws HibernateException {
if (begun) {
return;
}
if (commitFailed) {
throw new TransactionException("cannot re-start transaction after failed commit");
}
log.debug("begin");
try {
toggleAutoCommit = jdbcContext.connection().getAutoCommit();
if (log.isDebugEnabled()) {
log.debug("current autocommit status: " + toggleAutoCommit);
}
if (toggleAutoCommit) {
log.debug("disabling autocommit");
jdbcContext.connection().setAutoCommit(false);//把自动提交设为了false
}
} catch (SQLException e) {
log.error("JDBC begin failed", e);
throw new TransactionException("JDBC begin failed: ", e);
}
callback = jdbcContext.registerCallbackIfNecessary();
begun = true;
committed = false;
rolledBack = false;
if (timeout > 0) {
jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
}
jdbcContext.afterTransactionBegin(this);
}
在直接使用Hibernate时,要在事务结束的时候,写上一句:tx.commit(),这个commit()的源码为:
public void commit() throws HibernateException {
if (!begun) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("commit");
if (!transactionContext.isFlushModeNever() && callback) {
transactionContext.managedFlush(); // if an exception occurs during
// flush, user must call
// rollback()
}
notifyLocalSynchsBeforeTransactionCompletion();
if (callback) {
jdbcContext.beforeTransactionCompletion(this);
}
try {
commitAndResetAutoCommit();//重点代码,它的作用是提交事务,并把connection的autocommit属性恢复为true
log.debug("committed JDBC Connection");
committed = true;
if (callback) {
jdbcContext.afterTransactionCompletion(true, this);
}
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_COMMITTED);
} catch (SQLException e) {
log.error("JDBC commit failed", e);
commitFailed = true;
if (callback) {
jdbcContext.afterTransactionCompletion(false, this);
}
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
throw new TransactionException("JDBC commit failed", e);
} finally {
closeIfRequired();
}
}
上面代码中,commitAndResetAutoCommit()方法的源码如下:
private void commitAndResetAutoCommit() throws SQLException {
try {
jdbcContext.connection().commit();//这段不用说也能理解了
} finally {
toggleAutoCommit();//这段的作用是恢复connection的autocommit属性为true
}
}
上述代码的toggleAutoCommit()源代码如下:
private void toggleAutoCommit() {
try {
if (toggleAutoCommit) {
log.debug("re-enabling autocommit");
jdbcContext.connection().setAutoCommit(true);//这行代码的意义很明白了吧
}
} catch (Exception sqle) {
log.error("Could not toggle autocommit", sqle);
}
} 因此,如果你是直接使用hibernate,并手动管理它的session,并手动开启事务关闭事务的话,完全可以保证你的事务(好像完全是废话).
但是,如果你用的是HibernateTemplate,如同源代码1一样,则不要指望spring在关闭session的时候为你提交事务(罪魁祸首就是在代码1中调用了session.flush())。因为在使用代码1时,spring中得到session的方式如下:
Session session = (entityInterceptor != null ? sessionFactory.openSession(entityInterceptor) : sessionFactory
.openSession());简单地说它就是得到了一个session,而没有对connection的autocommit()作任何操作,spring管理范围内的session所持有的connection是autocommit=true的,spring借助这个属性,在它关闭session时,提交数据库事务。,因此如果你在源代码1中加上一句话:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
log.info(session.connection().getAutoCommit());//打印一下事务提交方式
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
}
});
} 运行后,它打出的结果是true,也就是说,虽然保存stu2时会报出例外,但如果commit属性为true,则每一个到达数据库的sql语句会立即被提交。换句话说,在调用完session.save(stu1)后,调用session.flush(),会发送sql语句到数据库,再根据commit属性为true,则保存stu1的操作已经被持久到数据库了,尽管后面的一条insert语句出了问题。
因此,如果你想在HibernateCallback中使用session的事务,需要如下写:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
//至于session的关闭就不用我们操心了
return null;
}
});
}运行上述代码,没问题了。至此,可能有些读者早就对代码1不满意了:为什么每次save()以后要调用flush()?这是有原因的。下面我们来看看把session.flush()去掉后会出什么问题。改掉后的代码如下:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
// session.flush();
session.connection().commit();
return null;
}
});
}运行上述代码,后台报数据库的not null错误,这个是合理的,打开数据库,没有发现新增记录,这个也是合理的。你可能会说:由于事务失败,数据库当然不可能会有任何新增记录。好吧,我们再把代码改一下,去除not null的错误,以确保它能正常运行。代码如下:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
stu2.setName("asdfasdf");//好了,这个字段设过值,不会再报not null错误了
session.save(stu2);
// session.flush();
session.connection().commit();
return null;
}
});
}
至此再运行上述代码,出现了一个奇怪的问题:
虽然控制台把insert语句打出来了,但是:数据库没有出现任何新的记录。
究其原因,有二:
一. session.connection().commit()确实导致数据库事务提交了,但是此刻session并没有向数据库发送任何语句。
二.在spring后继的flushIfNecessary()和closeSessionOrRegisterDeferredClose()方法中,第一个方法向数据库发送sql语句,第二个方法关闭session,同时关闭connection,然后问题在于:connection已经在程序中被手动设置为auttocommit=false了,因此在关闭数据库时,也不会提交事务。
解决这个问题很容易,在程序中手动调用session.flush()就可以了。如下代码:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();//向数据库发送sql
session.connection().commit();
return null;
}
});
}
运行上述代码,打开数据库查看,没有新增任何记录。在代码中新加一行stu2.setName("aaa");再次运行代码,发现数据库表中多了两条记录。事务操作成功。
至此,虽然操作成功,但事情还没有结束。这是因为spring在调用doInHibernate()的后继的步骤中,还要进行flushIfNecessary()操作,这个操作其实最后调用的还是session.flush()。因为在程序中已经手动调用过session.flush(),所以由spring调用的session.flush()并不会对数据库发送sql(因为脏数据比对的原因)。虽然不会对结果有什么影响,但是多调了一次flush(),还是会对性能多少有些影响。能不能控制让spring不调用session.flush()呢?可以的,只要加上一句代码,如下所示:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().setFlushMode(0);//0也就是FLUSH_NEVER
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
stu2.setName("sdf");
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
return null;
}
});
}通过设置HibernateTemplate的flushMode=FLUSH_NEVER来通知spring不进行session.flush()的调用,则spring的flushIfNecessary()将不进行任何操作,它的flushIfNecessary()源代码如下:
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
logger.debug("Eagerly flushing Hibernate session");
session.flush();
}
}至此,代码1中的main()终于修改完毕。但事实上,这样的操作无疑是比较麻烦的,因此如果在spring中想利用session进行事务操作时,最好还是用TransactionTemplate(编程式事务)或是声明式事务比较方便一些。
本例通过这么一个虽然简单但又绕来绕去的例子,主要是说明hibernate事务的一些内在特性,以及HibernateTemplate中如何处理session和事务的开关,让读者对HibernateTemplate的源代码处理细节有一些了解,希望能给读者有抛砖引玉的作用。
如果你这样写(1):
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();//实际上,如果不是程序员"手痒"来调用这个flush(),HibernateTemplate中session的事务处理还是很方便的
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
}
});
} 你期望spring在执行完execute回调后,在关闭session的时候提交事务,想法是很好的,但spring并不会这么做.让我们来看看在Hibernate的源代码中,session.beginTransation()做了什么事。看如下代码(2):
public Transaction beginTransaction() throws HibernateException {
errorIfClosed();
if ( rootSession != null ) {
// todo : should seriously consider not allowing a txn to begin from a child session
// can always route the request to the root session
log.warn( "Transaction started on non-root session" );
}
Transaction result = getTransaction();
result.begin();
return result;
}这个方法中的result是一个org.hibernate.transaction.JDBCTransaction实例,而方法中的getTransaction()方法源代码为(3):
public Transaction getTransaction() throws HibernateException {
if (hibernateTransaction==null) {
log.error(owner.getFactory().getSettings()
.getTransactionFactory().getClass());
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory()
.createTransaction( this, owner );
}
return hibernateTransaction;
}再次追踪,owner.getFactory().getSettings() .getTransactionFactory()的createTransaction()方法源代码如下(4):
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
throws HibernateException {
return new JDBCTransaction( jdbcContext, transactionContext );
}它返回了一个JDBCTransaction,没什么特别的。
在代码2中,执行了result.begin(),其实也就是JDBCTransaction实例的begin()方法,来看看(5):
public void begin() throws HibernateException {
if (begun) {
return;
}
if (commitFailed) {
throw new TransactionException("cannot re-start transaction after failed commit");
}
log.debug("begin");
try {
toggleAutoCommit = jdbcContext.connection().getAutoCommit();
if (log.isDebugEnabled()) {
log.debug("current autocommit status: " + toggleAutoCommit);
}
if (toggleAutoCommit) {
log.debug("disabling autocommit");
jdbcContext.connection().setAutoCommit(false);//把自动提交设为了false
}
} catch (SQLException e) {
log.error("JDBC begin failed", e);
throw new TransactionException("JDBC begin failed: ", e);
}
callback = jdbcContext.registerCallbackIfNecessary();
begun = true;
committed = false;
rolledBack = false;
if (timeout > 0) {
jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
}
jdbcContext.afterTransactionBegin(this);
}
在直接使用Hibernate时,要在事务结束的时候,写上一句:tx.commit(),这个commit()的源码为:
public void commit() throws HibernateException {
if (!begun) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("commit");
if (!transactionContext.isFlushModeNever() && callback) {
transactionContext.managedFlush(); // if an exception occurs during
// flush, user must call
// rollback()
}
notifyLocalSynchsBeforeTransactionCompletion();
if (callback) {
jdbcContext.beforeTransactionCompletion(this);
}
try {
commitAndResetAutoCommit();//重点代码,它的作用是提交事务,并把connection的autocommit属性恢复为true
log.debug("committed JDBC Connection");
committed = true;
if (callback) {
jdbcContext.afterTransactionCompletion(true, this);
}
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_COMMITTED);
} catch (SQLException e) {
log.error("JDBC commit failed", e);
commitFailed = true;
if (callback) {
jdbcContext.afterTransactionCompletion(false, this);
}
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
throw new TransactionException("JDBC commit failed", e);
} finally {
closeIfRequired();
}
}
上面代码中,commitAndResetAutoCommit()方法的源码如下:
private void commitAndResetAutoCommit() throws SQLException {
try {
jdbcContext.connection().commit();//这段不用说也能理解了
} finally {
toggleAutoCommit();//这段的作用是恢复connection的autocommit属性为true
}
}
上述代码的toggleAutoCommit()源代码如下:
private void toggleAutoCommit() {
try {
if (toggleAutoCommit) {
log.debug("re-enabling autocommit");
jdbcContext.connection().setAutoCommit(true);//这行代码的意义很明白了吧
}
} catch (Exception sqle) {
log.error("Could not toggle autocommit", sqle);
}
} 因此,如果你是直接使用hibernate,并手动管理它的session,并手动开启事务关闭事务的话,完全可以保证你的事务(好像完全是废话).
但是,如果你用的是HibernateTemplate,如同源代码1一样,则不要指望spring在关闭session的时候为你提交事务(罪魁祸首就是在代码1中调用了session.flush())。因为在使用代码1时,spring中得到session的方式如下:
Session session = (entityInterceptor != null ? sessionFactory.openSession(entityInterceptor) : sessionFactory
.openSession());简单地说它就是得到了一个session,而没有对connection的autocommit()作任何操作,spring管理范围内的session所持有的connection是autocommit=true的,spring借助这个属性,在它关闭session时,提交数据库事务。,因此如果你在源代码1中加上一句话:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
log.info(session.connection().getAutoCommit());//打印一下事务提交方式
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
}
});
} 运行后,它打出的结果是true,也就是说,虽然保存stu2时会报出例外,但如果commit属性为true,则每一个到达数据库的sql语句会立即被提交。换句话说,在调用完session.save(stu1)后,调用session.flush(),会发送sql语句到数据库,再根据commit属性为true,则保存stu1的操作已经被持久到数据库了,尽管后面的一条insert语句出了问题。
因此,如果你想在HibernateCallback中使用session的事务,需要如下写:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
//至于session的关闭就不用我们操心了
return null;
}
});
}运行上述代码,没问题了。至此,可能有些读者早就对代码1不满意了:为什么每次save()以后要调用flush()?这是有原因的。下面我们来看看把session.flush()去掉后会出什么问题。改掉后的代码如下:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
// session.flush();
session.connection().commit();
return null;
}
});
}运行上述代码,后台报数据库的not null错误,这个是合理的,打开数据库,没有发现新增记录,这个也是合理的。你可能会说:由于事务失败,数据库当然不可能会有任何新增记录。好吧,我们再把代码改一下,去除not null的错误,以确保它能正常运行。代码如下:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
stu2.setName("asdfasdf");//好了,这个字段设过值,不会再报not null错误了
session.save(stu2);
// session.flush();
session.connection().commit();
return null;
}
});
}
至此再运行上述代码,出现了一个奇怪的问题:
虽然控制台把insert语句打出来了,但是:数据库没有出现任何新的记录。
究其原因,有二:
一. session.connection().commit()确实导致数据库事务提交了,但是此刻session并没有向数据库发送任何语句。
二.在spring后继的flushIfNecessary()和closeSessionOrRegisterDeferredClose()方法中,第一个方法向数据库发送sql语句,第二个方法关闭session,同时关闭connection,然后问题在于:connection已经在程序中被手动设置为auttocommit=false了,因此在关闭数据库时,也不会提交事务。
解决这个问题很容易,在程序中手动调用session.flush()就可以了。如下代码:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();//向数据库发送sql
session.connection().commit();
return null;
}
});
}
运行上述代码,打开数据库查看,没有新增任何记录。在代码中新加一行stu2.setName("aaa");再次运行代码,发现数据库表中多了两条记录。事务操作成功。
至此,虽然操作成功,但事情还没有结束。这是因为spring在调用doInHibernate()的后继的步骤中,还要进行flushIfNecessary()操作,这个操作其实最后调用的还是session.flush()。因为在程序中已经手动调用过session.flush(),所以由spring调用的session.flush()并不会对数据库发送sql(因为脏数据比对的原因)。虽然不会对结果有什么影响,但是多调了一次flush(),还是会对性能多少有些影响。能不能控制让spring不调用session.flush()呢?可以的,只要加上一句代码,如下所示:
public static void main(String ss[]) {
CtxUtil.getBaseManager().getHibernateTemplate().setFlushMode(0);//0也就是FLUSH_NEVER
CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException, SQLException {
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
stu2.setName("sdf");
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
return null;
}
});
}通过设置HibernateTemplate的flushMode=FLUSH_NEVER来通知spring不进行session.flush()的调用,则spring的flushIfNecessary()将不进行任何操作,它的flushIfNecessary()源代码如下:
protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
logger.debug("Eagerly flushing Hibernate session");
session.flush();
}
}至此,代码1中的main()终于修改完毕。但事实上,这样的操作无疑是比较麻烦的,因此如果在spring中想利用session进行事务操作时,最好还是用TransactionTemplate(编程式事务)或是声明式事务比较方便一些。
本例通过这么一个虽然简单但又绕来绕去的例子,主要是说明hibernate事务的一些内在特性,以及HibernateTemplate中如何处理session和事务的开关,让读者对HibernateTemplate的源代码处理细节有一些了解,希望能给读者有抛砖引玉的作用。
评论
1 楼
Jason(aijun)
2008-09-18
HibernateTemplate确实没有设置session的事务属性,因为在spring的模型中,事务本来就不是HibernateTemplate来管理的。HibernateTemplate的作用是保证session能够正确的打开和关闭,避免手工管理session带来的问题,同时让session自动的参与事务,转换检查异常。spring中的事务应该使用TransactionTemplate,或者是是更加好的,类似EJB的声明式事务。如果配置了声明式事务,HibernateTemplate就可以保证让session自动参与事务,这一点从HibernateTemplate的源代码中可以看出来。手工管理的session在多线程操作,声明式事务的各种场景下,会造成代码的混乱。不推荐手工管理session,也不推荐手工管理事务。最佳的实践,是HibernateTemplate + 声明式事务。没有使用任何spring的事务机制,所以HibernateTemplate确实就是 无事务,这就是autoCommit==true的原因。
发表评论
-
java.util.ConcurrentModificationException
2012-05-15 14:15 837java.util.ConcurrentModificatio ... -
Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)
2010-04-15 13:35 1268什么是动态定时任务:是由客户制定生成的,服务端只知道该去执行什 ... -
Hibernate HQL查询
2009-07-09 15:32 2075Hibernate HQL查询 参数绑 ... -
editplus 编译 运行 执行 java 类
2009-03-26 16:50 1288关键字: editplus 编译 运行 执行 java 类 ... -
Resin:解决找不到com.sun.tools.javac.Main问题
2009-03-26 14:35 5206java.lang.ClassNotFoundExceptio ... -
Maven2 安装
2009-03-26 10:25 1964Maven2 安装 Maven 是一个构建工 ... -
jar打包详解
2008-10-16 15:51 1019为什么会有这个玩意呢 ... -
关于UML 2中结构图的介绍
2008-10-13 11:42 1832关于UML 2中结构图的 ... -
在 Java 中如何进行 BASE64 编码和解码
2008-10-09 09:47 1629BASE64 编码是一种常用的字符编码,在很多地方都会用到。 ... -
几种常见的异常
2008-10-08 17:12 748今天在做项目的时候报了这样一个错,所以我整理一些常见的异常,以 ... -
用PHP和MySQL保存和输出图片
2008-10-08 16:27 1417设置数据库 我们通常在数据库中所使用的文本 ... -
小议lIOC
2008-09-27 12:50 8651.ioc定义 IoC就是Inversion of Co ... -
读取显示当前目录下的文件及目录-java io
2008-09-24 18:04 2593很简单的一个需求,要求读取当前目录下所有的文件和目录,并显示出 ... -
為什么需要內部類
2008-09-24 18:00 791為什么需要內部類?有什么好處呢?感覺不用也沒什么,我也這樣任為 ... -
ext+dwr完整的例子(包括树, 增删改查等)
2008-09-23 08:40 1780---js var UI = function(){ v ... -
一个通用的ProxyMap
2008-09-19 09:23 2434先来一个通用的ProxyMap。如果不需要重用,这个类可以不用 ... -
声明式事务管理
2008-09-18 13:44 1623大多数Spring用户选择声 ... -
Spring中编程式事务处理(使用TransactionTemplate)
2008-09-18 11:39 4196Spring的编程式事务处理,需要使用Hibernate事务回 ... -
spring中使用编程级的事务
2008-09-18 10:56 2428使用org.springframework.transacti ... -
An internal error occurred during: Generating Art
2008-09-16 13:05 2778今天做项目遇到了这样一个问题:An internal erro ...
相关推荐
`HibernateTemplate`提供了多种事务处理机制,可以轻松集成到业务逻辑中,确保数据的一致性和完整性。 ```java hibernateTemplate.execute(new HibernateCallback() { public Void doInHibernate(Session ...
以下是一段示例代码,旨在演示如何使用`HibernateTemplate`进行多个数据库操作,并确保所有操作处于同一事务中: ```java public static void main(String[] args) { CtxUtil.getBaseManager()....
在这个例子中,开发者试图保存两个学生对象(stu1和stu2),期望它们在一个事务中完成。然而,由于`HibernateTemplate`的默认行为,当在`doInHibernate`内部调用`session.flush()`时,事务实际上已经被提交。这意味...
List list = hibernateTemplate.execute(new HibernateCallback() { @Override public List doInHibernate(Session session) throws HibernateException, SQLException { Query query = session.createQuery...
6. **Callback机制**:通过HibernateCallback接口,可以在Hibernate Session内部执行自定义操作,保持事务的一致性。 **三、使用示例** 在使用HibernateTemplate之前,需要配置SessionFactory,并将其注入到...
`HibernateTemplate`在事务管理、异常转换等方面提供了很多便利,而`HibernateDaoSupport`是一个抽象类,它的目的是为DAO提供对`HibernateTemplate`的便捷访问。 当我们在DAO中继承`HibernateDaoSupport`时,可以...
Spring通过HibernateTemplate和HibernateCallback接口,提供了对Hibernate ORM框架的集成。这使得开发者可以在不直接操作Session的前提下,方便地进行持久化操作。HibernateTemplate自动处理事务管理和资源关闭,...
Spring通过提供一系列的DAO抽象类,如HibernateDaoSupport,HibernateTemplate以及HibernateCallBack,使得开发者可以更方便地实现DAO组件。这些抽象类作为DAO实现类的基类,降低了开发难度,确保了代码的一致性和可...
- **Hibernate**:Spring通过HibernateTemplate和HibernateCallback接口,提供了对Hibernate的集成,使得我们可以利用Spring的DI和AOP来管理SessionFactory和Session。 - **MyBatis**:Spring支持MyBatis的...
HibernateTemplate支持`HibernateCallback`接口,允许在回调方法中执行自定义的Hibernate操作。这提供了一种方式在事务内部执行复杂操作,例如批量处理或自定义查询。开发者可以在实现`doInHibernate(Session ...
通常,程序中采用实现HibernateCallback的匿名内部类来获取HibernateCallback的实例,方法doInHibernate()就是Spring执行的持久化操作。 24.3 Spring对Hibernate的简化 24.3.5 HibernateDaoSupport Spring为与...
此外,Spring还提供了HibernateTemplate和HibernateCallback接口,使得事务管理变得更加简单。在`applicationContext.xml`中,我们需要配置Hibernate的相关bean,如SessionFactory、DataSource等。 对于Struts和...
在Spring框架中整合Hibernate是为了提供更高效、便捷的数据访问和事务管理能力。Spring整合Hibernate主要有以下三种方式: 1. **使用HibernateTemplate** HibernateTemplate是Spring早期为了简化Hibernate操作而...
此外,`HibernateTemplate`还支持`HibernateCallback`接口,允许开发者在回调方法`doInHibernate(Session session)`中使用原生的Hibernate API,以应对更复杂的数据访问需求。这种方法确保了灵活性,即使在Spring的...
AOP即面向切面编程,它允许将横切关注点(如日志、事务管理等)从业务逻辑中分离出来,通过声明式的方式动态地添加到程序中。 11. Spring AOP配置与应用: Spring AOP配置同样支持XML和注解方式。注解方式通过定义...
在上面的代码中,我们使用 `HibernateCallback` 接口来执行原生 SQL 语句,该接口提供了一个 `doInHibernate()` 方法,该方法将在 Hibernate 事务中执行。我们可以在该方法中执行原生 SQL 语句,并使用 `Connection`...
4. 使用`HibernateTemplate`或`HibernateCallback`接口来简化数据库操作。 **Spring与Struts的整合** 整合Spring和Struts有三种常见方式: 1. **Spring不管理Action(使用Spring的ActionSupport类整合Struts)** ...
return (List) hibernateTemplate.execute(new HibernateCallback<List<Person>>() { @Override public List<Person> doInHibernate(Session session) throws HibernateException { Criteria criteria = session...
`execute`方法会确保在事务中执行回调方法,这样可以保证数据库操作的原子性。`exposeNativeSession`参数决定是否暴露底层的JDBC Session给回调方法,这在需要直接使用原生SQL或者处理特定事务管理时非常有用。 总...
2. **ORM集成**:Spring通过`HibernateTemplate`和`HibernateCallback`支持Hibernate,简化了事务管理和对象关系映射。同样,对于MyBatis,Spring提供`SqlSessionFactoryBean`和`SqlSessionTemplate`来整合MyBatis,...