一、spring和Hibernate的集成(編程式事務(wù))(工程spring_hibernate_1
)
1.1 openSession
就是session = HibernateUtils.getSession();
獲得的session偷崩。如果有多個類使用該方法獲得session辟拷,那么將會有多個session。
1.2 currentSession
就是session = HibernateUtils.getSessionFactory().getCurrentSession();
獲得當(dāng)前線程的session阐斜。這樣如果有多個類衫冻,就可以使用此方法獲得session達(dá)到同步的效果。
1.3 openSession和currentSession的區(qū)別
- openSession必須關(guān)閉谒出,而currentSession在事務(wù)結(jié)束后自動關(guān)閉
- openSession沒有和當(dāng)前線程綁定隅俘,currentSession和當(dāng)前線程綁定
1.4 如果使用currentSession需要在hibernate.cfg.xml
文件中進(jìn)行配置
如果是本地事務(wù)(jdbc事務(wù))
<property name="hibernate.current_session_context_class">thread</property>
如果是全局事務(wù)(jta事務(wù))
<property name="hibernate.current_session_context_class">jta</property>
1.5 示例
實(shí)體類:
User.java
private int id;
private String name;
Log.java
private int id;
//操作日志、安全日志到推、事件日志
private String type;
private String detail;
private Date time;
配置文件:
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.usermgr.model">
<class name="User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
Log.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.usermgr.model">
<class name="Log" table="t_log">
<id name="id">
<generator class="native"/>
</id>
<property name="type"/>
<property name="detail"/>
<property name="time"/>
</class>
</hibernate-mapping>
UserManagerImpl.java
package com.bjsxt.usermgr.manager;
import java.util.Date;
import org.hibernate.Session;
import com.bjsxt.usermgr.model.Log;
import com.bjsxt.usermgr.model.User;
import com.bjsxt.usermgr.util.HibernateUtils;
public class UserManagerImpl implements UserManager {
public void addUser(User user) {
Session session = null;
try {
session = HibernateUtils.getSession();
//session = HibernateUtils.getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(user);
Integer.parseInt("asdfsdfsfsd");
Log log = new Log();
log.setType("安全日志");
log.setDetail("xxx進(jìn)入系統(tǒng)");
log.setTime(new Date());
LogManager logManager = new LogManagerImpl();
logManager.addLog(log);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}
說明:
1.上面我們使用的是傳統(tǒng)方式考赛,當(dāng)我們存入用戶之后再想要存入日志的時候,使用
addLog(log);
方法進(jìn)行保存日志莉测,但是在保存日志的時候我們需要一個session颜骤,同時我們注意到這兩個保存操作必須使用同一個session,當(dāng)然我們可以將session傳遞到日志記錄的業(yè)務(wù)類中捣卤,但是這樣hibernate就侵入到程序中了忍抽,在JavaEE中我們是使用的ThreadLocal類來保證這兩個操作使用的是同一個session,那么在hibernate中我們可以使用currentSession董朝,這個類就可以達(dá)到同步的效果鸠项。2.在程序中我們這樣得到currentSession:
session = HibernateUtils.getSessionFactory().getCurrentSession();
同時我們此時就不需要顯示關(guān)閉session了,同時在日志記錄業(yè)務(wù)類中我們也可以使用同樣的方法獲得當(dāng)前線程中的session子姜,實(shí)現(xiàn)同步祟绊。
LogManagerImpl.java
package com.bjsxt.usermgr.manager;
import com.bjsxt.usermgr.model.Log;
import com.bjsxt.usermgr.util.HibernateUtils;
public class LogManagerImpl implements LogManager {
public void addLog(Log log) {
HibernateUtils.getSessionFactory().getCurrentSession().save(log);
}
}
- 3.使用currentSession我們需要在hibernate的配置文件中進(jìn)行配置:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">jdbc:mysql://localhost/spring_hibernate_1</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">walp1314</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<!--
<property name="hibernate.current_session_context_class">jta</property>
-->
<mapping resource="com/bjsxt/usermgr/model/User.hbm.xml"/>
<mapping resource="com/bjsxt/usermgr/model/Log.hbm.xml"/>
</session-factory>
</hibernate-configuration>
可以看到我們需要根據(jù)事務(wù)的類型配置currentSession,所謂本地事務(wù)哥捕,就是基于JDBC的事務(wù)牧抽,可以理解為ThreadLocal,或者叫針對一個數(shù)據(jù)庫的事務(wù)遥赚;而全局事務(wù)可以理解為針對多個數(shù)據(jù)庫的事務(wù)扬舒。
注意:本例子是模擬我們進(jìn)行某種操作時,日志系統(tǒng)進(jìn)行相應(yīng)的記錄工作凫佛,這兩個工作必須是同步的讲坎。
二孕惜、spring和Hibernate的集成(采用聲明式事務(wù))(工程spring_hibernate_2
)
2.1 spring事務(wù)的傳播特性
<1>
PROPAGATION_REQUIRED
如果存在一個事務(wù),則支持當(dāng)前事務(wù)晨炕。如果沒有事務(wù)則開啟衫画,一般使用此傳播特性。<2>
PROPAGATION_SUPPORTS
如果存在一個事務(wù)府瞄,支持當(dāng)前事務(wù)碧磅。如果沒有事務(wù),則非事務(wù)的執(zhí)行遵馆,即不用事務(wù)。<3>
PROPAGATION_MANDATORY
如果已經(jīng)存在一個事務(wù)丰榴,支持當(dāng)前事務(wù)货邓。如果沒有一個活動的事務(wù),則拋出異常四濒。<4>
PROPAGATION_REQUIRES_NEW
總是開啟一個新的事務(wù)换况。如果一個事務(wù)已經(jīng)存在,則將這個存在的事務(wù)掛起盗蟆。<5>
PROPAGATION_NOT_SUPPORTED
總是非事務(wù)地執(zhí)行戈二,并掛起任何存在的事務(wù)。<6>
PROPAGATION_NEVER
總是非事務(wù)地執(zhí)行喳资,如果存在一個活動事務(wù)觉吭,則拋出異常。<7>
PROPAGATION_NESTED
如果一個活動的事務(wù)存在仆邓,則運(yùn)行在一個嵌套的事務(wù)中. 如果沒有活動事務(wù), 則按TransactionDefinition.PROPAGATION_REQUIRED
屬性執(zhí)行(spring特有的)
2.2 spring的隔離級別
<1>
ISOLATION_DEFAULT
這是一個PlatfromTransactionManager
默認(rèn)的隔離級別鲜滩,使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級別。另外四個與JDBC的隔離級別相對應(yīng)节值。<2>
ISOLATION_READ_UNCOMMITTED
這是事務(wù)最低的隔離級別徙硅,它充許令外一個事務(wù)可以看到這個事務(wù)未提交的數(shù)據(jù)。這種隔離級別會產(chǎn)生臟讀搞疗,不可重復(fù)讀和幻像讀嗓蘑。<3>
ISOLATION_READ_COMMITTED
保證一個事務(wù)修改的數(shù)據(jù)提交后才能被另外一個事務(wù)讀取。另外一個事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)匿乃。<4>
ISOLATION_REPEATABLE_READ
這種事務(wù)隔離級別可以防止臟讀桩皿,不可重復(fù)讀。但是可能出現(xiàn)幻像讀扳埂。它除了保證一個事務(wù)不能讀取另一個事務(wù)未提交的數(shù)據(jù)外业簿,還保證了避免下面的情況產(chǎn)生(不可重復(fù)讀)。<5>
ISOLATION_SERIALIZABLE
這是花費(fèi)最高代價但是最可靠的事務(wù)隔離級別阳懂。事務(wù)被處理為順序執(zhí)行梅尤。除了防止臟讀柜思,不可重復(fù)讀外,還避免了幻像讀巷燥。
2.3 示例
這里對于上面的示例我們不實(shí)用編程式事務(wù)了赡盘,而是交給spring進(jìn)行管理。首先需要配置sessionFactory缰揪、事務(wù)管理器陨享、事務(wù)的傳播特性和哪些類的哪些方法參與事務(wù),而這些配置我們一般放在一個公共的配置文件中:
applicationContext-common.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- 配置sessionFactory --><!-- 將相關(guān)配置注入到spring中 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- 配置事務(wù)管理器 --><!-- 將sessionFactory注入到spring的事務(wù)管理器中 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 配置事務(wù)的傳播特性 --><!-- 首先我們需要注入事務(wù)管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/><!-- 其他方法設(shè)置為只讀钝腺,可以提高效率 -->
</tx:attributes>
</tx:advice>
<!-- 哪些類的哪些方法參與事務(wù) -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution(* com.bjsxt.usermgr.manager.*.*(..))"/>
<aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/>
</aop:config>
</beans>
說明:對于將hibernate的配置文件注入到spring中時的classpath是spring實(shí)現(xiàn)的一個協(xié)議抛姑,讓spring可以找到hibernate的配置文件,于是我們hibernate的配置文件也可以不用默認(rèn)的名字艳狐。
對于需要注入sessionFactory的業(yè)務(wù)類我們可以單獨(dú)在一個配置文件中進(jìn)行配置:
applicationContext-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="userManager" class="com.bjsxt.usermgr.manager.UserManagerImpl">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="logManager" ref="logManager"/>
</bean>
<bean id="logManager" class="com.bjsxt.usermgr.manager.LogManagerImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">jdbc:mysql://localhost/spring_hibernate_2</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">walp1314</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<!--
<property name="hibernate.current_session_context_class">jta</property>
-->
<property name="dialect"></property>
<mapping resource="com/bjsxt/usermgr/model/User.hbm.xml" />
<mapping resource="com/bjsxt/usermgr/model/Log.hbm.xml" />
</session-factory>
</hibernate-configuration>
此時我們在業(yè)務(wù)類中使用的時候就需要繼承spring的HibernateDaoSupport類:
UserManagerImpl.java
package com.bjsxt.usermgr.manager;
import java.util.Date;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.bjsxt.usermgr.model.Log;
import com.bjsxt.usermgr.model.User;
import com.bjsxt.usermgr.util.HibernateUtils;
public class UserManagerImpl extends HibernateDaoSupport implements UserManager {
private LogManager logManager;
public void addUser(User user) throws Exception {
this.getHibernateTemplate().save(user);
Log log = new Log();
log.setType("安全日志");
log.setDetail("xxx進(jìn)入系統(tǒng)");
log.setTime(new Date());
logManager.addLog(log);
throw new Exception();
}
public void setLogManager(LogManager logManager) {
this.logManager = logManager;
}
}
LogManagerImpl.java
package com.bjsxt.usermgr.manager;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.bjsxt.usermgr.model.Log;
import com.bjsxt.usermgr.util.HibernateUtils;
public class LogManagerImpl extends HibernateDaoSupport implements LogManager {
public void addLog(Log log) {
this.getHibernateTemplate().save(log);
}
}
測試:Client.java
package com.bjsxt.usermgr.client;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.bjsxt.usermgr.manager.UserManager;
import com.bjsxt.usermgr.manager.UserManagerImpl;
import com.bjsxt.usermgr.model.User;
public class Client {
public static void main(String[] args) {
User user = new User();
user.setName("張三");
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");
try {
userManager.addUser(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
說明:在實(shí)際開發(fā)中我們一般使用注解的方式定硝,這在筆記(spring+struts2+Hibernate+maven+EasyUI開發(fā)環(huán)境搭建)中已經(jīng)說明了,這里不細(xì)說了毫目。