7、spring与hibernate的集成(spring笔记)

一、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开发环境搭建)中已经说明了,这里不细说了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容