一、依賴
maven依賴
1、依賴包版本
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>4.3.23.RELEASE</spring.version>
<hibernate.version>5.1.17.Final</hibernate.version>
<mysql.version>5.1.47</mysql.version>
<c3p0.version>0.9.2.1</c3p0.version>
<junit.version>4.12</junit.version>
<lombok.version>1.18.6</lombok.version>
</properties>
2、spring依賴包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
3、hibernate依賴包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
4、數據庫驅動包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
5、數據庫連接池
由於hibernate已經不再對dbcp提供支持,所以這裏使用的是c3p0
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
6、其他包(測試、工具)
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
二、在Spring中配置數據源
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/spring-data-test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
#jdbc.url=jdbc:mysql://localhost:3306/spring-data-test 這個保存到數據庫中會導致亂碼
jdbc.driver.class=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456
applicationContext.xml
<!-- 配置讀取properties文件的工具類 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置c3p0數據庫連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="driverClass" value="${jdbc.driver.class}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
三、在Spring中配置hibernate的sessionFactory
<!-- 配置hibernate的sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- hibernateProperties屬性:配置與hibernate相關內容,如顯示sql語句,開啓正向工程 -->
<property name="hibernateProperties">
<value>
<!-- hibernate.dialect=org.hibernate.dialect.HSQLDialect -->
<!-- 顯示當前執行的sql -->
hibernate.show_sql=true
<!-- 開啓正向工程 -->
hibernate.hbm2ddl.auto=update
<!--SQL格式化-->
hibernate.format_sql=true
</value>
</property>
<!-- 掃描實體所在的包 -->
<property name="packagesToScan">
<list>
<value>com.mzj.spring.pojo</value>
</list>
</property>
</bean>
其中hibernateProperties常用的屬性有:
hibernate.dialect |
dialect就是“方言”,因爲hibernate是要把Java對象轉換成關係數據庫來描述的,而關係數據庫雖然有一些統一的標準,如SQL-92等。 但是實際上各數據庫如Oracle,MySQL,MS SQL Server等等爲了提高性能或增加功能都提供了一些額外的標準或語法,因此,hibernate爲了更好適配各種關係數據庫,針對每種數據庫都指定了一個方言dialect。 |
hibernate.show_sql | 是否顯示執行的sql語句,取值:true/false |
hibernate.hbm2ddl.auto |
開啓正向工程,取值說明: validate:加載hibernate時,驗證創建數據庫表結構 create:每次加載hibernate,重新創建數據庫表結構,這就是導致數據庫表結構丟失的原因 create-drop:加載hibernate時創建,退出是刪除表結構 update:加載hibernate自動更新數據庫結構 |
hibernate.format_sql | 是否對sql進行格式化顯示輸出,,取值:true/false |
四、在Spring中配置springIOC的註解掃描
<!-- 配置springIOC的註解掃描 -->
<context:component-scan base-package="com.mzj.spring"></context:component-scan>
五、在Spring中配置HibernateTemplate對象
目的是可以在業務DAO實現類中注入HibernateTemplate對象,並通過操作此對象完成數據庫訪問。
<!-- 配置HibernateTemplate對象 -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
六、編碼
1、實體bean
package com.mzj.spring.pojo;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name="ts_users")
@Data
public class Users implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Long id;
@Column(name="user_name")
private String userName;
@Column(name="age")
private Integer age;
}
2、Dao接口
package com.mzj.spring.dao;
import com.mzj.spring.pojo.Users;
public interface UsersDao {
void insertUsers(Users users);
void updateUsers(Users users);
void deleteUsers(Users users);
Users selectUserById(Long id);
}
3、Dao接口實現
通過注入的HibernateTemplate實現對數據庫的訪問
package com.mzj.spring.dao.impl;
import com.mzj.spring.dao.UsersDao;
import com.mzj.spring.pojo.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UsersDaoImpl implements UsersDao {
@Autowired
private HibernateTemplate hibernateTemplate;
public void insertUsers(Users users) {
this.hibernateTemplate.save(users);
}
public void updateUsers(Users users) {
this.hibernateTemplate.update(users);
}
public void deleteUsers(Users users) {
this.hibernateTemplate.delete(users);
}
public Users selectUserById(Long id) {
return this.hibernateTemplate.get(Users.class, id);
}
}
七、四種事務管理方式
通過上面的設置可以使得Spring和Hibernate完成整合,下面開始說Spring管理Hibernate事務的四種管理方式:
第一種方式,利用tx標籤配置事務。
<!-- a. 配置事務容器 -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- b. 定義事務規則 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- c. 定義事務入口(那些類的哪些方法參與事務) -->
<aop:config>
<aop:pointcut expression="execution(* com.cn.tch.spring_hibernate2.*.*(..))"
id="pt" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
</aop:config>
下面也給出幾種傳播特性的解釋:
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 屬性執行。
第二種方式,使用代理進行配置
<!-- 配置事務容器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 定義事務規則 -->
<bean id="transactionProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<!-- ,回滾爲-,不回滾爲+ -->
<prop key="update">PROPAGATION_SUPPORTS,-Exception</prop>
</props>
</property>
</bean>
<!-- 定義事務入口 -->
<bean id="deptProxy" parent="transactionProxy">
<property name="target" ref="deptDao"></property>
</bean>
在使用代理管理事務時,如果需要使用到getCurrentSession()這個方法,需要設置(這裏所說的有點像是第四種管理方式的配置,有可能代理模式不支持使用getCurrentSession()):
<tx:annotation-driven transaction-manager="transactionManager" />
同時需要在service上添加@Transactional,不然會報錯:org.hibernate.HibernateException: No Session found for current thread
第三種方式,使用攔截器
<!-- 配置事務容器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 定義事務規則 -->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<!-- 回滾爲-,不回滾爲+ -->
<prop key="update">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,+MyException</prop>
</props>
</property>
</bean>
<!-- 定義事務入口 -->
<bean id="proxyFactory"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
<property name="beanNames">
<list>
<value>deptDao</value>
</list>
</property>
</bean>
第四種方式,使用註解方式
第一步:在 xml 配置文件中添加事務配置信息。除了用配置文件的方式,@EnableTransactionManagement 註解也可以啓用事務管理功能
<!-- 配置hibernate的事務管理器 -->
<!-- 配置事務容器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置開啓【註解事務】處理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
第二步:在service類或者方法上面添加@Transactional註解。
- @Transactional 註解添加到類級別上時,表示所有該類的公共方法都配置相同的事務屬性信息;
- 方法級別如果也配置了@Transactional,應用程序會以方法級別的事務屬性信息來管理事務,換言之,方法級別的事務屬性信息會覆蓋類級別的相關配置信息。
- @Transactional 註解的常用屬性信息:
屬性名 | 說明 |
name | 當在配置文件中有多個 TransactionManager , 可以用該屬性指定選擇哪個事務管理器 |
propagation | 事務的傳播行爲,默認值爲 REQUIRED。 |
isolation | 事務的隔離度,默認值採用 DEFAULT。 |
timeout | 事務的超時時間,默認值爲-1。如果超過該時間限制但事務還沒有完成,則自動回滾事務。 |
readOnly | 指定事務是否爲只讀事務,默認值爲 false;爲了忽略那些不需要事務的方法,比如讀取數據,可以設置 read-only 爲 true。 |
rollbackFor | 用於指定能夠觸發事務回滾的異常類型,如果有多個異常類型需要指定,各類型之間可以通過逗號分隔。 |
noRollbackFor | 拋出 no-rollback-for 指定的異常類型,不回滾事務。 |
- 屬性使用舉例:@Transactional(noRollbackFor=ProcessException.class)那他是什麼意思呢?一句話,在你聲明的這個事物裏如果發生了ProcessException這個異常就noRollBack,就是數據庫事務不發生回滾。就這麼簡單
縱觀以上四種在Spring中配置Hibernate事務的方法,其核心都是一樣的,不同的只是實現的方式而已。所以看到這,這篇博文中你只需要記住4句話,就可以輕鬆理解在Spring中配置Hibernate事務的核心:
1.配置SessionFactory
2.配置事務容器
3.配置事務規則
4.配置事務入口
Spring的註解方式實現事務管理機制擴展閱讀:
https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
(如果對 Spring 中的 @transaction 註解的事務管理理解的不夠透徹,就很容易出現錯誤,比如事務應該回滾(rollback)而沒有回滾事務的問題。)
示例完整spring配置文件內容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mzj.spring</groupId>
<artifactId>spring-hibernate</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-hibernate</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>4.3.23.RELEASE</spring.version>
<hibernate.version>5.1.17.Final</hibernate.version>
<mysql.version>5.1.47</mysql.version>
<c3p0.version>0.9.2.1</c3p0.version>
<junit.version>4.12</junit.version>
<lombok.version>1.18.6</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
測試類(注意@Test中事務默認是回滾的,因此採用main函數進行測試):
package com.mzj.spring;
import com.mzj.spring.dao.UsersDao;
import com.mzj.spring.pojo.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class TestTransaction {
@Autowired
private UsersDao userDao;
@Transactional(noRollbackFor = RuntimeException.class)
public void insert(){
Users users = new Users();
users.setAge(18);
users.setUserName("路飛55");
this.userDao.insertUsers(users);
if (true){
throw new RuntimeException();
}
Users users2 = new Users();
users2.setAge(33);
users2.setUserName("路飛66");
this.userDao.insertUsers(users2);
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
TestTransaction testTransaction = context.getBean(TestTransaction.class);
testTransaction.insert();
}
}
完整工程地址:E:\01.study\04.spring\04.integration\hibernate\springhibernate
由於比較簡單,沒有上傳github