2016年1月23日 星期六

Hibernate 3.x 整合 Spring 3.x

Hibernate3.x 整合 Spring3.x可以不需要hibernate.cfg.xml,就先以這為例



※XML設定

pom.xml


<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.2.13.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.2.13.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>3.2.13.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
    
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.10.Final</version>
</dependency>
    
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.19.0-GA</version>
</dependency>

※雖然不用hibernate.cfg.xml,但jar檔當然還是要,而hibernate-core會用到javassist,所以也要下載

※如果不喜歡用DBCP,可以用C3P0,可參考Spring 管理 JdbcTemplate、DBCP、C3P0、JdbcDaoSupport (Spring3.x 二十三)的最後一項



applicationContext.xml

<context:annotation-config />
<context:component-scan base-package="dao.impl" />
    
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />
    <property name="username" value="username" />
    <property name="password" value="password" />
</bean>
    
<bean id="sf"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="ds" />
    <property name="mappingResources">
        <list>
            <value>hbm/Dept.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.use_sql_comments">true</prop>
        </props>
    </property>
</bean>
    
<bean id="ht" class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory" ref="sf" />
</bean>

※可以從這裡複製,然後再修改,比較不會錯,最後的bean沒得複製,這行是因為Spring有提供一個叫HibernateTemplate的東西,相當於Hibernate的org.hibernate.Session

※props也可用如下的寫法:
<value>
    hibernate.dialect=org.hibernate.dialect.OracleDialect
    hibernate.show_sql=true
    hibernate.format_sql=true
    hibernate.use_sql_comments=true
</value>



IDept.java

public interface IDept {
    public boolean insert(Dept dept);
    public List<Dept> QueryAll();
}



DeptImpl.java

@Repository
public class DeptImpl extends HibernateDaoSupport implements IDept {
    @Autowired
    public DeptImpl(HibernateTemplate ht) {
        super.setHibernateTemplate(ht);
    }
    
    // 不用HibernateTemplate
    @Autowired
    private SessionFactory sf;
    
    @Override
    public boolean insert(Dept dept) {
        return super.getHibernateTemplate().save(dept) != null;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public List<Dept> QueryAll() {
        // 不用HibernateTemplate
        Session session = sf.openSession();
        Query q = session.createQuery("from Dept");
        return q.list();

        // return super.getHibernateTemplate().find("from Dept");
    }
}



測試類

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
for (String s : ctx.getBeanDefinitionNames()) {
    System.out.println(s);
}
    
IDept dao = ctx.getBean("deptImpl", IDept.class);
Dept vo = new Dept();
vo.setDname("業務部");
vo.setLoc("舊金山");
System.out.println(dao.insert(vo));
    
for (Dept d : dao.QueryAll()) {
    System.out.println(d.getDname());
}
    
((ClassPathXmlApplicationContext) ctx).close();


※此次專案圖



※Annotation設定

可參考API,package是org.springframework.orm.hibernate3.annotation,裡面只有一隻class,叫AnnotationSessionFactoryBean

將XML設定的applicationContext.xml的sf改成以下的樣子,注意class不同了

applicationContext.xml

<bean id="sf"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="ds" />
    <property name="annotatedClasses">
        <list>
            <value>vo.Dept</value>
        </list>
    </property>    
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.use_sql_comments">true</prop>
        </props>
    </property>
</bean>

※屬性名稱annotatedClasses下面放class就搞定了


Dept.java

@Entity
@Table
public class Dept {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX")
    @SequenceGenerator(name = "XXX", sequenceName = "DEPT_SEQ")
    private Integer deptno;
    
    private String dname;
    
    private String loc;
    // setter/getter...
}





※getCurrentSession

如果想使用CurrentSession還要設定


applicationContext.xml

<tx:annotation-driven transaction-manager="txManagerHibernate" />
    
<bean id="txManagerHibernate"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sf" />
</bean>
    
<bean id="txManagerJDBC"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="ds" />
</bean>
    
    
<!-- LocalSessionFactoryBean的hibernateProperties,這兩個prop不用設定 -->
<prop key="hibernate.current_session_context_class">
    org.springframework.orm.hibernate3.SpringSessionContext
</prop>
    
<prop key="hibernate.transaction.factory_class">
    org.springframework.orm.hibernate3.SpringTransactionFactory
    org.hibernate.transaction.JTATransactionFactory
</prop>

※txManagerHibernate和txManagerJDBC擇其一,其實還有JTA,看官網

※hibernate.current_session_context_class要設就設這個,執行LocalSessionFactoryBean時,裡面其實就會幫我們加了(底層的589行),但整合就不能使用thread了

※hibernate.transaction.factory_class,執行LocalSessionFactoryBean就會幫我們判斷加其中之一了,不要設定



DeptImpl.java

@Transactional
public boolean insert(Dept dept) {
    Session session = sf.getCurrentSession();
    
    Dept dept1 = new Dept();
    dept1.setDeptno(160);
    dept1.setDname("業務部");
    dept1.setLoc("舊金山");
    
    session.save(dept);
    session.save(dept1);
    
    return true;
}
    
@Transactional(readOnly = true)
public List<Dept> QueryAll() {
    //...
}

※applicationContext.xml設定完了還不夠,還得在方法上加@Transactional,這樣子不用顯式的呼叫commit、rollback,就可以自動幫我們完成commit、rollback了

※雖然是select,還是要加@transactional,不然一樣會報錯;加上readOnly = true效能會比較好


※還可以applicationContext.xml和hibernate.cfg.xml都並存,還有針對特定的方法名執行transaction,看Hibernate4.x 整合 Spring3.x

沒有留言:

張貼留言