一、spring和Hibernate的集成(编程式事务)(工程spring_hibernate_1
)
1.1 openSession
就是session = HibernateUtils.getSession();
获得的session。如果有多个类使用该方法获得session,那么将会有多个session。
1.2 currentSession
就是session = HibernateUtils.getSessionFactory().getCurrentSession();
获得当前线程的session。这样如果有多个类,就可以使用此方法获得session达到同步的效果。
1.3 openSession和currentSession的区别
- openSession必须关闭,而currentSession在事务结束后自动关闭
- openSession没有和当前线程绑定,currentSession和当前线程绑定
1.4 如果使用currentSession需要在hibernate.cfg.xml
文件中进行配置
-
如果是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
-
如果是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>
1.5 示例
实体类:
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进入系统");
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.上面我们使用的是传统方式,当我们存入用户之后再想要存入日志的时候,使用
addLog(log);
方法进行保存日志,但是在保存日志的时候我们需要一个session,同时我们注意到这两个保存操作必须使用同一个session,当然我们可以将session传递到日志记录的业务类中,但是这样hibernate就侵入到程序中了,在JavaEE中我们是使用的ThreadLocal类来保证这两个操作使用的是同一个session,那么在hibernate中我们可以使用currentSession,这个类就可以达到同步的效果。 -
2.在程序中我们这样得到currentSession:
session = HibernateUtils.getSessionFactory().getCurrentSession();
同时我们此时就不需要显示关闭session了,同时在日志记录业务类中我们也可以使用同样的方法获得当前线程中的session,实现同步。
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的配置文件中进行配置:
<!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>
可以看到我们需要根据事务的类型配置currentSession,所谓本地事务,就是基于JDBC的事务,可以理解为ThreadLocal,或者叫针对一个数据库的事务;而全局事务可以理解为针对多个数据库的事务。
注意:本例子是模拟我们进行某种操作时,日志系统进行相应的记录工作,这两个工作必须是同步的。
二、spring和Hibernate的集成(采用声明式事务)(工程spring_hibernate_2
)
2.1 spring事务的传播特性
-
<1>
PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启,一般使用此传播特性。 -
<2>
PROPAGATION_SUPPORTS
如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行,即不用事务。 -
<3>
PROPAGATION_MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。 -
<4>
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。 -
<5>
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。 -
<6>
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。 -
<7>
PROPAGATION_NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED
属性执行(spring特有的)
2.2 spring的隔离级别
-
<1>
ISOLATION_DEFAULT
这是一个PlatfromTransactionManager
默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。 -
<2>
ISOLATION_READ_UNCOMMITTED
这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 -
<3>
ISOLATION_READ_COMMITTED
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 -
<4>
ISOLATION_REPEATABLE_READ
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。 -
<5>
ISOLATION_SERIALIZABLE
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
2.3 示例
这里对于上面的示例我们不实用编程式事务了,而是交给spring进行管理。首先需要配置sessionFactory、事务管理器、事务的传播特性和哪些类的哪些方法参与事务,而这些配置我们一般放在一个公共的配置文件中:
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 --><!-- 将相关配置注入到spring中 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- 配置事务管理器 --><!-- 将sessionFactory注入到spring的事务管理器中 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 配置事务的传播特性 --><!-- 首先我们需要注入事务管理器 -->
<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"/><!-- 其他方法设置为只读,可以提高效率 -->
</tx:attributes>
</tx:advice>
<!-- 哪些类的哪些方法参与事务 -->
<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实现的一个协议,让spring可以找到hibernate的配置文件,于是我们hibernate的配置文件也可以不用默认的名字。
对于需要注入sessionFactory的业务类我们可以单独在一个配置文件中进行配置:
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>
此时我们在业务类中使用的时候就需要继承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进入系统");
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();
}
}
}
说明:在实际开发中我们一般使用注解的方式,这在笔记(spring+struts2+Hibernate+maven+EasyUI开发环境搭建)中已经说明了,这里不细说了。
网友评论