SSH组合之Spring3整合Hibernate4(一)

1、在Spring里,Hibernate的资源要交给Spring来管理。Hibernate及其SessionFactory等只是Spring一个特殊的Bean,由Spring负责实例化与销毁。

由于Hibernate全部交给Spring来管理,HIbernate不再需要自己的配置文件,所有的参数都在Spring的src/applicationContext.xml中配置

2、详细步骤

(1)新建web project

-->Add Spring Capabilities(勾选前5个)

-->Add Hibernate Capabilities(core、advanced support)

-->配置文件选择放在Spring的applicationContext.xml

-->配置DataSource

jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8

com.mysql.jdbc.Driver

-->不创建Session Factorry class

-->finish !

(2)加入mysql的驱动lib,否则“Cannot load JDBC driver class 'com.mysql.jdbc.Driver”

(3)applicationContext.xml

配置数据库的dataSource

配置sessionFactory

配置Dao层

配置Spring的Hibernate事务管理器 (Aop:aspect)

配置事务的传播特性

配置事务的管理位置(Aop:pointcut)

<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 
           http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver">
        </property>
        <property name="url"
            value="jdbc:mysql://localhost:3306/ztravel?characterEncoding=UTF-8">
        </property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.MySQLDialect
                </prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.current_session_context_class">
                    org.springframework.orm.hibernate4.SpringSessionContext
                </prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <!-- 解决nested exception is org.hibernate.HibernateException: Error applying 
                    BeanValidation relational constraints -->
                <prop key="javax.persistence.validation.mode">none</prop>
            </props>
        </property>
        <!-- 配置实体类,与数据库的表有关 -->
        <property name="annotatedClasses">
            <list>
                <!-- 注意大小写 -->
                <value>com.z.hibernate.bean.Agency</value>
                <value>com.z.hibernate.bean.Discount</value>
                <value>com.z.hibernate.bean.Group</value>

                <value>com.z.hibernate.bean.Manager</value>

            </list>
        </property>
    </bean>

    <!-- 配置Dao ,class是实现接口的类-->
    <bean id="dao" class="com.z.hibernate.dao.impl.DaoImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    
        <!-- struts2的Action -->
    <!-- scope默认为singleston,这里一定要设置 成prototype。这样浏览器每次请求一次,spring都会生成一个新的Action对象-->
    <bean id="viewAction" scope="prototype" class="com.z.strust2.action.ViewAction">
    <!--iDao是操作数据库的接口,dao是一个bean的id名  -->
    <property name="iDao" ref="dao"></property>
    </bean>
    
    <!-- 配置事务管理Spring的Hibernate事务管理器 (Aop:aspect) 责任:负责session的开启和关闭,负责事物的开启,管理和回滚(遇到RunTimeException会自动回滚,其他异常不会) -->
    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 配置事务的传播特性 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="merge*" propagation="REQUIRED" />
            <tx:method name="del*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />
            <tx:method name="put*" propagation="REQUIRED" />
            <tx:method name="use*" propagation="REQUIRED" />
            <!--hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到 -->
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="count*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" read-only="true" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <!-- 配置事务的管理位置(Aop:pointcut) 。在哪些地方切入事务的管理 -->
    <aop:config expose-proxy="true">
        <!-- 只对业务逻辑层实施事务 -->
        <!-- 添加实现了接口的类到里面 -->
        <aop:pointcut id="txPointcut"
            expression="execution(* com.z.hibernate.dao..*.*(..)) OR execution(* com.xp.common..*.*(..))" />
        <!-- pointcut-ref的值要与 aop:pointcut的id一致 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
    </aop:config>
</beans>

需要注意的问题:

1、execution(* com.dao..*.*(..))表示com.dao包里面的类都在事务管理范围之内,需要根据情况改动

如果一个类有getSession().save(cat);类似操作,则必须被包含

2、别忘了在annotatedClasses配置实体类

3、如果需要根据2中的实体类自动建表,别忘了

<prop key="hibernate.hbm2ddl.auto">update</prop>

4、dao记得配置

5、<!-- 解决nested exception is org.hibernate.HibernateException: Error applying BeanValidation relational constraints -->

<prop key="javax.persistence.validation.mode">none</prop>

6、在开发Spring的过程中,有时会出现Eclipse不能识别<tx:advice/>标签。 

这个错误的原因是:我们在定义申明AOP的时候,没有加载schema。 

7. cannot simultaneously fetch multiple bags  

当一个实体对象中包含多于一个non-lazy获取策略时,比如@OneToMany,@ManyToMany或者@ElementCollection时,获取策略为(fetch = FetchType.EAGER)

出现问题的原因:

当(fetch = FetchType.EAGER)多余一个时,持久框架抓取一方的对象时,同时又将多方的对象加载进容器中,多方又可能关联其它对象,Hibernate实现的JPA,默认最高抓取深度含本身级为四级(它有个属性配置是0-3),若多方(第二级)存在重复值,则第三级中抓取的值就无法映射,就会出现 multiple bags。

解决方法:

1、将(fetch = FetchType.EAGER)改为(fetch = FetchType.LAZY)

2、将List修改成Set集合,即推荐@ManyToMany或@OneToMany的Many方此时用Set容器来存放,而不用List集合。

3、改变FetchMode为@Fetch(FetchMode.SUBSELECT),即发送另外一条select语句抓取前面查询到的所有实体对象的关联实体。

4、在对应的属性上添加@IndexColumn,该注解允许你指明存放索引值的字段,目的跟Set容器不允许重复元素的道理一样。

推荐的处理办法:

方法2;

方法3和方法4是Hibernate特有的,非JPA标准;

如果可以用方法1,那就不会出现这个问题。

 8、org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.life.hibernate.bean.Coupon.users, no session or session was closed

方法:在onttomany端设置fetch=FetchType.EAGER

9、org.hibernate.PersistentObjectException: detached entity passed to persist: com.life.hibernate.bean.Store

是级联配置不对:
把cascade = CascadeType.ALL 改成 cascade=CascadeType.REFRESH 。

3、接口IDao

package com.z.hibernate.dao;
import java.util.List;
public interface IDao<T> {

    /**
     * 增加
     * @param object
     */
    public void save(T object);
    /**
     * 删除
     * @param object
     */
    public void delete(T object);
    /**
     * 增加
     * @param object
     */
    public void update(T object);
    /**
     * 根据传进来的HQL语句更新,返回受影响行数
     * @param hql
     * @return
     */
    public int updateByQuery(String hql);
    /**
     * 查询
     * @param hql
     * @param parameter
     * @return
     */
    public List<T> list(String hql,Object... parameter);
    /**
     * 获取记录总数
     * @param hql
     * @param params
     * @return
     */
    public int getTotalCount(String hql,Object...params);
}

4、实现接口DaoImpl<T>

package com.z.hibernate.dao.impl;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.z.hibernate.dao.IDao;

public class DaoImpl<T> implements IDao<T> {
    private SessionFactory sessionFactory;

    @Override
    public void save(T object) {
        // TODO Auto-generated method stub
        getSession().save(object);
    }

    @Override
    public void delete(T object) {
        // TODO Auto-generated method stub
        getSession().delete(object);
    }

    @Override
    public void update(T object) {
        // TODO Auto-generated method stub
        getSession().saveOrUpdate(object);
    }

    @Override
    public List<T> list(String hql, Object... parameter) {
        // TODO Auto-generated method stub
        Query query = getSession().createQuery(hql);
        if (parameter != null) {
            for (int i = 0; i < parameter.length; i++) {
                query.setParameter(i, parameter[i]);
            }
        }
        List<T> list = query.list();
        return list;
    }

    @Override
    public int getTotalCount(String hql, Object... params) {
        // TODO Auto-generated method stub
        return 0;
    }

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    // 必须要有get-set,不然会Error creating bean with name 'sessionFactory' defined in
    // class path resource
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public int updateByQuery(String hql) {
        // TODO Auto-generated method stub
        int k = sessionFactory.getCurrentSession().createQuery(hql)
                .executeUpdate();
        return k;
    }
}

需要注意的问题

1、SessionFactory 必须要有get/set

4、得到并调用Dao的方法

注意

IDao<Manager>是接口,在xml配置”dao“的bean的class是实现接口的类
        BeanFactory factory=new ClassPathXmlApplicationContext("applicationContext.xml");
        IDao<Manager> iDao=factory.getBean("dao",IDao.class);
        Manager manager=new Manager();
        manager.setM_account("11");
        manager.setM_pwd("gtg");
        iDao.save(manager);

如果项目导入了struts2框架并进行了相关配置,则不需要通过factory.getBean("catDao",CatDao.class);这种方式获取对象

Done!

原文地址:https://www.cnblogs.com/xingyyy/p/3596246.html