工程結構
問題描述
在工程中通過spring aop的方式配置事務,使用hibernate做持久化。在代碼實現中使用hibernate persit()方法插入數據到數據庫,使用hibernate update()方法更新數據。問題是執行這兩個方法沒有報錯,但是也沒有插入數據或者更新數據。
原因
hibernate persist()以及update()方法只有事務執行flush()或者commit()方法,才將數據寫入數據庫。詳細內容可以閱讀博客:http://www.cnblogs.com/xiaoheike/p/5374613.html。使用spring aop配置的事務,在方法運行結束之后會運行commit()方法。程序實例可以看PersonDAOImpl.java(實現方法)小結,重點原因在於spring aop事務與session自己創建的事務是兩個不同的事務,雖然最后spring aop 配置的事情 commit,但是session對象的事務並沒有調用commit。以下是實例程序。
事務配置(applicationContext.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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/Testdb" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hiberante.format_sql">true</prop>
</props>
</property>
<!-- hibernate配置文件放置位置,這個配置文件似乎也沒有多大的作用了 -->
<property name="configLocations">
<list>
<value>
classpath:/hibernate.cfg.xml
</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:advice id="personServiceTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 表達式中的這些方法會執行如下的規則 -->
<tx:method name="delete*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" />
<tx:method name="update*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" />
<tx:method name="save*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" />
<tx:method name="*" isolation="DEFAULT" read-only="false" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="personServiceTxPointcut" expression="execution(* com.journaldev.dao.PersonDAO.*(..))" />
<aop:advisor id="personServiceTxAdvisor" advice-ref="personServiceTxAdvice" pointcut-ref="personServiceTxPointcut" />
</aop:config>
<bean id="personDAO" class="com.journaldev.dao.PersonDAOImpl">
<property name="sessionFactory1" ref="sessionFactory" />
<property name="sessionFactory2" ref="sessionFactory" />
</bean>
</beans>
PersonDAOImpl.java(實現方法)
package com.journaldev.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.model.Person;
public class PersonDAOImpl implements PersonDAO {
private SessionFactory sessionFactory1;
private SessionFactory sessionFactory2;
public void setSessionFactory1(SessionFactory sessionFactory1) {
this.sessionFactory1 = sessionFactory1;
}
public void setSessionFactory2(SessionFactory sessionFactory2) {
this.sessionFactory2 = sessionFactory2;
}
public void save1(Person person) {
Session session1 = this.sessionFactory1.openSession();
session1.persist(person);
session1.close();
}
public void save2(Person person) {
Session session1 = this.sessionFactory1.openSession();
Session session2 = sessionFactory2.openSession();
Transaction tx = session2.beginTransaction();
session1.persist(person);
tx.commit();
session2.close();
session1.close();
}
public void save3(Person person) {
Session session1 = this.sessionFactory1.openSession();
Transaction tx = session1.beginTransaction();
session1.persist(person);
tx.commit();
session1.close();
}
@SuppressWarnings("unchecked")
public List<Person> list() {
Session session = this.sessionFactory1.openSession();
List<Person> personList = session.createQuery("from Person").list();
session.close();
return personList;
}
public Person findOne(Integer id) {
Session session = this.sessionFactory1.openSession();
Person p = (Person) session.get(Person.class, id);
session.close();
return p;
}
public void delete(Person person) {
Session session = this.sessionFactory1.openSession();
session.delete(person);
session.close();
}
public void update1(Person person) {
Session session = this.sessionFactory1.openSession();
session.update(person);
session.close();
}
public void update2(Person person) {
Session session1 = this.sessionFactory1.openSession();
Session session2 = this.sessionFactory1.openSession();
Transaction tx = session2.beginTransaction();
session1.update(person);
tx.commit();
session2.close();
session1.close();
}
public void update3(Person person) {
Session session1 = this.sessionFactory1.openSession();
Transaction tx = session1.beginTransaction();
session1.update(person);
tx.commit();
session1.close();
}
}
測試類
package com.journaldev.main;
import java.util.List;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.dao.PersonDAO;
import com.journaldev.model.Person;
public class SpringHibernateMain {
public static void main(String[] args) {
test1();
test2();
test3();
}
public static void test1() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDAO personDAO = context.getBean(PersonDAO.class);
System.out.println("=================save1()==================");
// 增加一條數據
Person person = new Person();
person.setName("Pankaj");
person.setCountry("India");
personDAO.save1(person);
System.out.println("================listAll()===================");
// 檢索所有數據
List<Person> list = personDAO.list();
for (Person p : list) {
System.out.println("所有記錄:" + p);
}
System.out.println("================update1()===================");
// 更新一條Person記錄
person.setCountry("zhongguo");
personDAO.update1(person);
System.out.println("更新一條記錄India-->zhongguo:" + personDAO.findOne(person.getId()));
System.out.println("================delete()===================");
// 刪除一條Person記錄
personDAO.delete(person);
context.close();
}
public static void test2() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDAO personDAO = context.getBean(PersonDAO.class);
System.out.println("=================save3()==================");
// 增加一條數據
Person person = new Person();
person.setName("Pankaj");
person.setCountry("India");
personDAO.save1(person);
System.out.println("================listAll()===================");
// 檢索所有數據
List<Person> list = personDAO.list();
for (Person p : list) {
System.out.println("所有記錄:" + p);
}
System.out.println("================update2()===================");
// 更新一條Person記錄
person.setCountry("zhongguo");
personDAO.update1(person);
System.out.println("更新一條記錄India-->zhongguo:" + personDAO.findOne(person.getId()));
System.out.println("================delete()===================");
// 刪除一條Person記錄
personDAO.delete(person);
context.close();
}
public static void test3() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDAO personDAO = context.getBean(PersonDAO.class);
System.out.println("=================save3()==================");
// 增加一條數據
Person person = new Person();
person.setName("Pankaj");
person.setCountry("India");
personDAO.save3(person);
System.out.println("================listAll()===================");
// 檢索所有數據
List<Person> list = personDAO.list();
for (Person p : list) {
System.out.println("所有記錄:" + p);
}
System.out.println("================update3()===================");
// 更新一條Person記錄
person.setCountry("zhongguo");
personDAO.update3(person);
System.out.println("更新一條記錄India-->zhongguo:" + personDAO.findOne(person.getId()));
System.out.println("================delete()===================");
// 刪除一條Person記錄
personDAO.delete(person);
context.close();
}
}
運行結果
=================save1()==================
================update1()===================
Hibernate: select person0_.id as id1_0_0_, person0_.country as country2_0_0_, person0_.name as name3_0_0_ from PERSON person0_ where person0_.id=?
更新一條記錄India-->zhongguo:null
=================save2()==================
================update2()===================
Hibernate: select person0_.id as id1_0_0_, person0_.country as country2_0_0_, person0_.name as name3_0_0_ from PERSON person0_ where person0_.id=?
更新一條記錄India-->zhongguo:null
=================save3()==================
Hibernate: insert into PERSON (country, name) values (?, ?)
================update3()===================
Hibernate: update PERSON set country=?, name=? where id=?
Hibernate: select person0_.id as id1_0_0_, person0_.country as country2_0_0_, person0_.name as name3_0_0_ from PERSON person0_ where person0_.id=?
更新一條記錄India-->zhongguo:id=8, name=Pankaj, country=zhongguo
原因分析
一共有三個測試例子,第一個例子test1()方法,調用save1()方法,使用spring aop配置的事務,從輸出結果可以看出,數據沒有插入數據庫。update1()方法與save1()方法是相同情況。
第二個例子test2()方法,調用save2()方法,persist()方法被包圍在spring aop配置的事務和session2的事務中(事務有提交),從輸出結果可以看出,數據沒有插入數據庫。update2()方法與save2()方法是相同情況。
第三個例子test3()方法,persist()方法被包圍在spring aop配置的事務和session1的事務中(事務有提交),從輸出結果可以看出,數據成功插入數據庫。update3()方法與save3()方法是相同情況。
通過實例程序可以看出,persist(),以及update()方法需要在調用它們的session中的事務中執行,最后該session的事務需要commit。
源代碼可以從github獲取:https://github.com/xiaoheike/SpringHibernateWithTransactionExample,這份源代碼是spring + hibernate + spring aop 配置事務的demo工程。在完成demo過程中發現該問題,一直無法理解,一周之后恍然大悟,遂寫這篇博客。
教程結束,感謝閱讀。
歡迎轉載,但請注明本文鏈接,謝謝。
2016/4/15 18:38:01