??xml version="1.0" encoding="utf-8" standalone="yes"?>
Hibernate可以配置?/SPAN>JDBCTransaction或者是JTATransactionQ这取决于你?/SPAN>hibernate.properties中的配置:
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
如果你什么都不配|,默认情况下?/SPAN>JDBCTransactionQ如果你配置为:
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
?/SPAN>JTATransaction不管你准备让Hibernate使用JDBCTransactionQ还?/SPAN>JTATransactionQ我的忠告就是什么都不配Q将让它保持默认状态,如下Q?/SPAN>
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
在下面的分析中我会给出原因?/SPAN>
一?/SPAN>JDBC Transaction
看看使用JDBC Transaction的时候我们的代码例子Q?/SPAN>
Session session = sf.openSession();
Transaction tx = session.beginTransactioin();
...
session.flush();
tx.commit();
session.close();
q是默认的情况,当你在代码中使用Hibernate?/SPAN>Transaction的时候实际上是JDBCTransaction。那?/SPAN>JDBCTransactionI竟是什么东西呢Q来看看源代码就清楚了:
Hibernate2.0.3源代码中的类
net.sf.hibernate.transaction.JDBCTransaction:
public void begin() throws HibernateException {
...
if (toggleAutoCommit) session.connection().setAutoCommit(false);
...
}
q是启动Transaction的方法,看到connection().setAutoCommit(false) 了吗Q是不是很熟悉? 再来?/SPAN>
public void commit() throws HibernateException {
...
try {
if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
try {
session.connection().commit();
committed = true;
}
...
toggleAutoCommit();
}
q是提交ҎQ看?/SPAN>connection().commit() 了吗Q下面就不用我多说了Q这个类代码非常单易懂,通过阅读使我们明?/SPAN>Hibernate?/SPAN>Transaction都在q了些什么?我现在把?/SPAN>Hibernate写的例子译?/SPAN>JDBCQ大家就一目了然了Q?/SPAN>
Connection conn = ...; <--- session = sf.openSession();
conn.setAutoCommit(false); <--- tx = session.beginTransactioin();
... <--- ...
conn.commit(); <--- tx.commit(); (对应左边的两?/SPAN>)
conn.setAutoCommit(true);
conn.close(); <--- session.close();
看明白了吧,Hibernate?/SPAN>JDBCTransactionҎ是conn.commit而已Q根本毫无神U可aQ只不过?/SPAN>Hibernate中,Session打开的时候,׃自动conn.setAutoCommit(false)Q不像一般的JDBCQ默认都?/SPAN>trueQ所以你最后不?/SPAN>commit也没有关p,׃Hibernate已经?/SPAN>AutoCommitl关掉了Q所以用Hibernate的时候,你在E序中不?/SPAN>Transaction的话Q数据库Ҏ没有反应?/SPAN>
二?/SPAN>JTATransaction
如果你在EJB中?/SPAN>HibernateQ或者准备用JTA来管理跨Session的长事务Q那么就需要?/SPAN>JTATransactionQ先看一个例子:
javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
...
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
tx.commit();
q是标准的?/SPAN>JTA的代码片断,Transaction是跨Session的,它的生命周期?/SPAN>Session要长。如果你?/SPAN>EJB中?/SPAN>HibernateQ那么是最单不q的了,你什?/SPAN>Transaction代码l统都不要写了,直接?/SPAN>EJB的部|描q符上配|某某方法是否用事务就可以了?/SPAN>
现在我们来分析一?/SPAN>JTATransaction的源代码
net.sf.hibernate.transaction.JTATransaction:
public void begin(InitialContext context, ...
...
ut = (UserTransaction) context.lookup(utName);
...
看清楚了吗? 和我上面写的代码 tx = new Initial
Context?().lookup("javax.transaction.UserTransaction");
是不是完全一P
public void commit() ...
...
if (newTransaction) ut.commit();
...
JTATransaction的控制稍微复杂,不过仍然可以很清楚的看出?/SPAN>Hibernate是如何封?/SPAN>JTA?/SPAN>Transaction代码的?/SPAN>
但是你现在是否看C什么问题? 仔细想一下,Hibernate Transaction是从Session中获得的Q?/SPAN>tx = session.beginTransaction()Q最后要先提?/SPAN>txQ然后再session.closeQ这完全W合JDBC?/SPAN>Transaction的操作顺序,但是q个序是和JTA?/SPAN>Transactioin操作序d矛盾的!Q!
JTA是先启动TransactionQ然后启?/SPAN>SessionQ关?/SPAN>SessionQ最后提?/SPAN>TransactionQ因此当你?/SPAN>JTA?/SPAN>Transaction的时候,那么千万不要?/SPAN>Hibernate?/SPAN>TransactionQ而是应该像我上面?/SPAN>JTA的代码片断那样用才行?/SPAN>
ȝQ?/SPAN>
1、在JDBC上?/SPAN>Hibernate 必须写上Hibernate Transaction代码Q否则数据库没有反应。此?/SPAN>Hibernate?/SPAN>Transaction是Connection.commit而已
2、在JTA上?/SPAN>Hibernate ?/SPAN>JTA?/SPAN>Transaction代码Q不要写Hibernate?/SPAN>Transaction代码Q否则程序会报错
3、在EJB上?/SPAN>Hibernate 什?/SPAN>Transactioin代码都不要写Q在EJB的部|描q符里面配置
|---CMT(Container Managed Transaction)
|
|---BMT(Bean Managed Transaction)
|
|----JDBC Transaction
|
|----JTA Transaction
提问Q?/SPAN>
javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
...
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
tx.commit();
s1不关闭,使用s2q行操作的代码中使用s1可不可以Q我觉得q样更加节约资源Q不需要反复的q接、关闭)?/SPAN>sf.opengSession()Ӟq没?/SPAN>setAutoCommit(false)Q我想问的是Q如果不~写M事务代码Q如Q?/SPAN>
Session s = sf.openSession();
......
s.close();
数据库会不会有反应(此时应该是默?/SPAN>AutoCommit?/SPAN>trueQ?/SPAN>
不会有反应。在sf.openSession()
创徏Session实例的时候,已l调用了conn.setAutoCommit(false)了?/SPAN>
另外Q我想问一下:
<code>
1. s.flush()是不是必ȝ
2. s.close()是不是一定要关闭
</code>
回答Q?/SPAN>
s.flush不是必须的,s.close()会调用一?/SPAN>s.flush()
s.close()正常情况下应该关闭,除非你是?/SPAN>ThreadLocal理Session?/SPAN>
s1不关闭,使用s2q行操作的代码中使用s1可不可以Q我觉得q样更加节约资源Q不需要反复的q接、关闭)</code>
在这个例子中看不出来JTA的作用?/SPAN>
假设
<code>Class A {
find() {
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
}
}</code>
<code>Class B {
find() {
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
}
}
Main {
tx = ...;
A.find();
B.find();
tx.commit();
}
看明白了吗?JTA?/SPAN>Transaction理是跨c调用的?/SPAN>
1. 在mySQL中徏立一张USER表?/P>
CREATE TABLE USER (
user_id CHAR(32) NOT NULL PRIMARY KEY,
name VARCHAR(16) NOT NULL,
sex CHAR(1),
age INT
);
2. 建立一个pojo
package com.xy;
public class User {
private String id;
private String name;
private char sex;
private int age;
public int getAge() {
return age;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public char getSex() {
return sex;
}
public void setAge(int i) {
age = i;
}
public void setId(String string) {
id = string;
}
public void setName(String string) {
name = string;
}
public void setSex(char c) {
sex = c;
}
}
3. hibernate.cfg.xml文g
<?xml version='1.0' encoding='utf-8'?> <hibernate-configuration> <session-factory> <!-- 昄实际操作数据库时的SQL --> <!-- 映射文g --> </session-factory> </hibernate-configuration> 4. User.hbm.xml <?xml version="1.0"?> <hibernate-mapping> <class name="com.xy.User" table="USER"> <id name="id" type="string" unsaved-value="null"> <property name="name" type="string" not-null="true"> <property name="sex" type="char"/> <property name="age" type="int"/> </class> </hibernate-mapping> 5. 试文g package com.xy; import java.util.List; import org.apache.commons.logging.Log; import net.sf.hibernate.*; public class HibernateTest { Session session = sessionFactory.openSession(); List users = session.find("from User"); session.close(); for (ListIterator iterator = users.listIterator(); iterator } public void insert() { SessionFactory sessionFactory; User user = new User(); Session session = sessionFactory.openSession(); System.out.println("插入数据OK!请在MySQL查看l果Q?); public static void main(String[] args) throws HibernateException { new HibernateTest().find(); } 6. 文gl构和所用到的jar?BR>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"
<property name="show_sql">true</property>
<!-- SQL方言Q这里设定的是MySQL -->
<property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
<!-- JDBC驱动E式 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- JDBC URL -->
<property name="connection.url">jdbc:mysql://localhost/jiejie</property>
<!-- 用户?-->
<property name="connection.username">root</property>
<!-- 密码-->
<property name="connection.password"></property>
<mapping resource="User.hbm.xml"/>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"
<column name="user_id" sql-type="char(32)" />
<generator class="uuid.hex"/>
</id>
<column name="name" length="16" not-null="true"/>
</property>
import java.util.ListIterator;
import org.apache.commons.logging.LogFactory;
import net.sf.hibernate.cfg.*;
private static Log log = LogFactory.getLog(HibernateTest.class);
public void find() {
SessionFactory sessionFactory;
try {
sessionFactory = new Configuration().configure()
.buildSessionFactory();
sessionFactory.close();
.hasNext();) {
User user = (User) iterator.next();
System.out.println(user.getName() + "\n\tAge: " + user.getAge()
+ "\n\tSex: " + user.getSex());
}
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
sessionFactory = new Configuration().configure()
.buildSessionFactory();
user.setName("caterpillar");
user.setSex('M');
user.setAge(23);
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
sessionFactory.close();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
new HibernateTest().insert();
}
7. 操作l果
log4j:WARN No appenders could be found for logger (net.sf.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select user0_.user_id as user_id, user0_.name as name, user0_.sex as sex, user0_.age as age from USER user0_
caterpillar
Age: 28
Sex: M
caterpillar
Age: 28
Sex: M
caterpillar
Age: 28
Sex: M
caterpillar
Age: 23
Sex: M
qqqqq
Age: 20
Sex: M
www
Age: 21
Sex: M
yyy
Age: 20
Sex: M
yyy
Age: 20
Sex: M
yyy
Age: 20
Sex: M
yyy
Age: 20
Sex: M
Hibernate: insert into USER (name, sex, age, user_id) values (?, ?, ?, ?)
插入数据OK!请在MySQL查看l果Q?BR>