Spring 持久層整合
Spring 持久層整合
文章目錄
1 持久層整合
1.1 Spring框架為什麼要與持久層技術進行整合
1. JavaEE開發需要持久層進行資料庫的訪問操作。
2. JDBC Hibernate MyBatis進行持久層開發過程中存在大量的冗餘
3. Spring基於模板設計模式對於上述的持久層技術進行了封裝
1.2 Spring可以與哪些持久層技術進行整合?
1. JDBC
|- JDBCTemplate
2. Hibernate
|- HibernateTemplate
3. MyBatis
|- SqlSessionFactoryBean MapperScannerConfigurer
2 Spring與MyBatis整合
2.1 MyBatis 開發步驟的回顧
1. 實體
2. 實體別名 配置繁瑣
3. 表
4. 建立dao介面
5. 實現mapper檔案
6. 註冊的mapper檔案 配置繁瑣
7. MyBatis API呼叫 程式碼冗餘
2.2 MyBatis在開發過程中存在問題
配置繁瑣 程式碼冗餘
2.3 Spring與MyBatis 整合思路分析
- SqlSessionFactoryBean
- dataSource
- typeAliasesPackage
- mapperLocations
- (可有) configLocation
- MapperScannerConfigure
- sqlSessinFactoryBeanName
- basePackage
2.4 Spring與Mybatis整合的開發步驟
-
配置檔案(application.xml) 進行相關配置
<!--配置 只需要配置--> <!--建立SqlSessionFactory--> <bean id ="ssfb" class="..SqlSessionFactoryBean"> <property name = "dataSouce" ref = ""/> <property name = "typeAliasesPackage" value = "com.leetao.dao"/>指定 實體類所在的包 <property name = "mapperLocations"> 指定 配置檔案(對映檔案)的路徑 還有通用配置 mapper/*Mapper.xml </property> </bean> <!--建立DAO介面的實現類--> <!--session -> session.getMapper() -> xxxDAO實體類物件 --> <!-- XXXDAO -> xXXDAO --> <bean id = "scanner" class = "..MapperScannerConfigure"> <property name = "sqlSessionFactoryBeanName" value = "ssfb" /> <property name = "basePackage"> 指定 DAO介面放置的包 com.leetao.dao </property> </bean>
-
編碼
# 實戰經常根據需求 寫的程式碼 1. 實體 2. 表 3. 建立dao介面 4. 實現mapper檔案
2.5 Spring與MyBatis整合程式碼
- 搭建開發環境(jar)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
-
Spring配置檔案的配置
<context:property-placeholder location="classpath:db.properties"/> <!--連線池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--建立SqlSessionFactory SqlSessionFactoryBean--> <bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.leetao.mybatis.domain"/> <property name="mapperLocations"> <list> <value>classpath:com.leetao.mybatis.mapper/*Mapper.xml</value> </list> </property> </bean> <!--建立DAO物件 mapperScannerConfigure--> <bean id="scanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/> <property name="basePackage" value="com.leetao.mybatis.mapper"/> </bean>
-
編碼
1. 實體 2. 表 3. 建立dao介面 4. mapper檔案配置
2.6 Spring與MyBatis整合的細節
-
問題:Spring與MyBatis整合後,為什麼DAO不提交事務,但是資料能夠插入資料庫中?
Connection -->tx MyBatis(Connection) ------------------------------------ 本質上控制連線物件(Connection) ---> 連線池(DataSource) 1. Mybatis 提供的連線池物件 --> 建立Connection Connection.setAutoCommit(false) 手工的控制了事務,操作完成後,手動提交 2. Druid(C3P0 DBCP)作為連線池 -->建立Connection Connection.setAutoCommit(true) true預設值,保持自動控制事務,一條sql 自動提交 ----------------------------------- 注意:在未來實戰中,我們還會手工控制事務(多條sql一起成功,一起失敗),後續Spring通過事務控制解決這個問題 事實上所有上面這些連線池都是自動提交的 包括 pooledDataSource 以上為孫帥老師講解. 1. 菅江暉個人認為 mybatis沒整合之前 使用SqlSession來獲取Mapper.而SqlSession預設是不自動提交的. 2. mybatis與Spring整合後.使用SqlSessionTemplase類通過動態代理建立來執行Mapper方法.SqlSessionTemplase中的SqlSession其實也是不自動提交的,其中invoke方法中會判讀是否為sql會話事務.如果不是將會提交.同時執行結束後也會關閉sqlSession 這也解釋了為什麼使用代理後的mapper 無需手動建立 關閉sqlsession 都是動態代理的功勞 AOP
3 Spring的事務處理
3.1 什麼是事務? ACID
保證業務操作完整性的一種資料庫機制
事務4特點 A C I D
1. A 原子性
2. C 一致性
3. I 隔離性
4. D 永續性
3.2 如何控制事務
JDBC:
Connection.setAutoCOmmit(false);
Connection.commit();
COnnetion.rollback();
MyBatis:
MyBatis自動開始事務
SqlSession(Connection).commit();
SqlSession(Connection).rollback();
結論:控制事務的底層,都是Connection物件完成的.
3.3 Spring控制事務的開發
Spring是通過AOP的方式進行事務開發的
-
原始物件
public class xxxUserServiceImpl{ 1.原始物件---> 原始方法 ---> 核心功能(業務處理+DAO呼叫) 2.DAO作為Service的成員變數,依賴注入的方式進行賦值 }
-
額外功能
1. org.springframework.jdbc.datasource.DataSourceTransactionManager 2. 注入DataSource 1. MethodInterceptor --------------------------------------------------------- public Object invoke(MethodInvocation invocation) { Connection.setAutoCommit(false); invocation.proceed(); Connection.commit(); if throw Exception Commction.rollback(); } 2. @Aspect @Around
-
切入點
@Transactional 事務的額外功能加入給那些業務方法. 1.類上:類中所有方法都會加入事務 2.方法上:這個方法會加入事務
-
組裝切面
1. 切入點 2. 額外功能 <tx:annotaion-driven transaction-manager="" />
3.4 Spring控制事務的編碼
-
搭建開發環境(jar)
-
編碼
<bean id = "userService" class="com.leetao.mybatis.service.impl.UserServiceImpl"> <property name="userMapper" ref="userMapper"/> </bean> <!--DataSourceTransactionManager--> <bean id = "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> -------------------------- @Transactional public class UserServiceImpl implements UserService {} -------------------------- <tx:annotation-driven transaction-manager = "dataSourceTransactionManager"/>
-
細節
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" proxy-target-class="true"/> 進行動態代理底層的切換 proxy-target-class 預設 false JDK true Cglib
4 Spring中的事務屬性 Transaction Attribute
4.1 什麼是事務屬性
屬性:描述物體特徵的一系列值
性別 身高 體重 ...
事務屬性:描述事務特徵的一系列值
1. 隔離屬性
2. 傳播屬性
3. 只讀屬性
4. 超時屬性
5. 異常屬性
4.2 如何新增事務屬性
@Transactional(isolation=,propagation=
readOnly=,timeout=,rollbackFor=,noRollbackFor=,)
4.3 事務屬性詳解
4.3.1 隔離事務(ISOLATION)
-
隔離屬性的概念
概念: 他描述了事務解決併發問題的特徵 1. 什麼是併發 多個事務(使用者)在同一時間,訪問操作了相同的資料 同一時間: 0.000幾秒 微小前,微小後 2. 併發會產生哪些問題 1.髒讀 2.不可重複讀 3.幻影讀 3. 併發問題如何解決 通過隔離屬性解決 隔離屬性中設定不同的值,解決併發處理過程中的問題.
-
事務併發產生的問題
1.髒讀
一個事務,讀取了另一個事務中沒有提交的資料.會在本事務中產生資料不一致的問題. 解決方案: @Transactional(isolation=Isolation.READ_COMMITTED)
2.不可重複讀
一個事務中,多次讀取相同的資料,但是讀取結果不一樣.會在本事務中產生資料不一致的問題 注意:1 不是髒讀 2 一個事務中 解決方案: @Transactional(isolation=Isolation.REPEATABLE_READ) 本質 行鎖
3.幻影讀
一個事務中,多次對整表進行查詢統計,但是結果不一樣,會在本事務中產生資料不一致的問題 解決方案: @Transactional(isolation.SERIALIZABLE) 本質 表鎖
-
總結
併發安全: SERIALIZABLE > REPEATABLE > READ_COMMITTED 執行效率:READ_COMMITTED > REPEATABLE > SERIALIZABLE
-
資料庫對於隔離屬性的支援
隔離屬性的值 | MySQL | Oracle |
---|---|---|
ISOLATION.READ_COMMENTTED | ✔ | ✔ |
ISOLATION.REPEATABLE_READ | ✔ | |
ISOLATION.SERIALIZABLE | ✔ | ✔ |
Oracle不支援REPEATABLE_READ值 如何解決不可重複讀
採用的是多版本對比的方式 解決不可重複讀的問題
-
預設隔離屬性
ISOLATION_DEFAULT:會第哦啊用不同資料庫所設定額預設隔離屬性 MySQL -> REPEATABLE_READ Oracle -> READ_COMMITTED
-
MySQL
select @@tx_isolation;
-
Oracle
-
-
隔離屬性在實戰中的建議
推薦使用Spring指定排程ISOLATION.DEFAULT MySQL -> REPEATABLE_READ Oracle -> READ_COMMITTED 未來中的實戰中,併發訪問情況 很低 如果真遇到併發問題,樂觀鎖 Hibernate(JPA) Version MyBatis 通過攔截器自定義開發
4.3.2 傳播屬性(PROPAGATION)
-
傳播屬性的概念
概念:他描述了事務解決巢狀問題的特徵 什麼叫做事務的巢狀:一個大的事務中,包含了若干個小的事務. 問題:大事務中融入了很多小的事務,他們彼此影響,最終導致大的事務喪失了事務的原子性
傳播屬性的值 外部不存在事務 外部存在事務 用法 備註 REQUIRED 開啟新的事務 融合 @Transactional(propagation=Propagation.REQUIRED) 增刪改 SUPPORTS 不開啟事務 融合 @Transactional(propagation=Propagation.SUPPORTS) 查詢 REQUIRES_NEW 開啟新的事務 掛起外部事物,建立新的事務 @Transactional(propagation=Propagation.REQUIRES_NEW) 日誌記錄方法中 NOT_SUPPORTED 不開啟事務 掛起外部事務 @Transactional(propagation=Propagation.NOT_SUPPORTED) 極其不常用 NEVER 不開啟事務 丟擲異常 @Transactional(propagation=Propagation.NEVER) 極其不常用 MANDATORY 丟擲事務 融合到外部事務中 @Transactional(propagation=Propagation.MANDATORY) 極其不常用 -
預設的傳播屬性
REQUIRED是傳播屬性的預設值
-
推薦傳播屬性的使用方式
增刪改 方法:直接使用預設的REQUIRED 查詢 操作:顯示指定傳播屬性的值為SUPPORTS
4.3.3 只讀屬性(readOnly)
針對於只進行查詢操作的業務方法,可以加入只讀屬性,提高執行效率
預設值:false
4.3.4 超時屬性(timeout)
指定了事務等待的最長時間
1. 為什麼事務進行等待?
當前事務訪問資料時,有可能訪問的資料被別的事務進行加鎖的處理,那麼此時本事務就必須進行等待.
2. 等待時間 秒
3. 如何應用 @Transactional(timeout=2)
4. 超時屬性的預設值 -1
最終由對應的資料庫來指定
4.3.5 異常屬性
Spring 事務處理中
預設 對於RuntimeException及其子類 採用的是回滾的策略
預設 對於Exception 採用的是提交的策略
//讓他回滾
rollbackFor = (..Exception,*Exception)
//讓他不回滾
noRollbackFor = (..RuntimeException)
@Trancastional(rollbackFor= {java.lang.Exception.class},noRollbackFor = {java.lang.RuntimeException.class})
建議:實戰中使用RuntimeException極其子類 使用事務異常屬性的預設值.
4.4 事務屬性常見配置總結
1. 隔離屬性 預設值
2. 傳播屬性 Required(預設值) 增刪改 Supports 查詢操作
3. 只讀屬性 false(預設值) 增刪改 true 查詢操作
4. 超時屬性 預設值 -1
5. 異常屬性 預設值
增刪 改操作 @Transactional
查詢操作 @Transactional(Propagation=Propagetion.SUPPORTS,readOnly=true)
5 基於標籤的事務配置方式(事務開發的第二種形式)
基於註解 @Transactional的事務配置回顧
<bean id = "userService" class="com.leetao.mybatis.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper"/>
</bean>
<!--DataSourceTransactionManager-->
<bean id = "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
@Transactional
public class UserServiceImpl implements UserService { }
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
基於標籤的事務配置
<bean id = "userService" class="com.leetao.mybatis.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper"/>
</bean>
<!--DataSourceTransactionManager-->
<bean id = "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
事務屬性
<tx:advice id = "txAdvice" transaction-manager = "dataSourceTransactionManager">
<tx:attributes>
<tx:method name = "register"isolation = "" propagation=""></tx:method>
等效於
@Transactional(isolation=,propagation=,)
public void register(){
}
</tx:attributes>
</tx:advice>
<!--AOP -->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.leetao.mybatis.service..*(..))"/>
<aop:advisor advice-ref="interceptor" pointcut-ref="pc"/>
</aop:config>
- 基於標籤的事務配置在實戰中的應用方式
<bean id = "userService" class="com.leetao.mybatis.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper"/>
</bean>
<!--DataSourceTransactionManager-->
<bean id = "dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
程式設計時候 servie中負責進行增刪改操作的方法 都以modify開頭
查詢 命名無所謂
<tx:advice id="txAdvice" transaction-manager = "dataSOurceTransactionManager">
<tx:attributes>
<!--先配置的優先順序更高-->
<tx:method name = "modify*"></tx:method>
<tx:method name = "*" propagation="SUPPORTS" readOnly="true"></tx:method>
</tx:attributes>
</tx:advice>
應用的過程中,service放置到service包中
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.leetao.mybatis.service..*.*(..))"/>
<aop:advisor advice-ref="interceptor" pointcut-ref="pc"/>
</aop:config>
約定大於配置
異常彙總
BeanCurrentlyInCreationException Bean迴圈依賴異常
檢查程式碼 分析錯誤
相關文章
- RxCache 整合 Android 的持久層框架 greenDAO、RoomAndroid框架OOM
- Java資料持久層Java
- 使用Spring Data JPA實現持久化層的簡化開發Spring持久化
- Java 持久層框架之 MyBatisJava框架MyBatis
- SpringBoot2 基礎案例(09):整合JPA持久層框架,簡化資料庫操作Spring Boot框架資料庫
- 河青的持久層框架hqbatis框架BAT
- Java持久層框架Mybatis入門Java框架MyBatis
- spring盒springMVC整合父子容器問題:整合Spring時Service層為什麼不做全域性包掃描詳解SpringMVC
- MyBatis--優秀的持久層框架MyBatis框架
- MicroStream + Helidon高效能Java持久層ROSJava
- 持久層Mybatis3底層原始碼分析,原理解析MyBatisS3原始碼
- Spring Boot整合Spring SecuritySpring Boot
- Spring Boot整合Spring BatchSpring BootBAT
- Spring Boot整合Spring AopSpring Boot
- 淺談Mybatis持久化框架在Spring、SSM、SpringBoot整合的演進及簡化過程MyBatis持久化框架SSMSpring Boot
- 自己動手寫一個持久層框架框架
- MyBatis(九) 整合Spring、整合SpringMVCMyBatisSpringMVC
- mybatis整合springMyBatisSpring
- Spring 整合 HibernateSpring
- ActiveMq整合SpringMQSpring
- Spring Cloud 整合SpringCloud
- Spring 整合 MyBatisSpringMyBatis
- Spring整合WebSocketSpringWeb
- Spring整合JUnitSpring
- Spring整合MyBatisSpringMyBatis
- spring:spring與mybatis的整合SpringMyBatis
- Spring Boot:整合Spring Data JPASpring Boot
- MVVM的資料持久化(一)——ROOM的整合MVVM持久化OOM
- spring+redis的整合,使用spring-data-redis來整合SpringRedis
- spring-boot 整合 spring-securitySpringboot
- spring-boot 整合 spring-sessionSpringbootSession
- Spring Boot整合Spring Cloud Netflix元件Spring BootCloud元件
- 整合RabbitMQ&SpringMQSpring
- Spring與ActiveMQ整合SpringMQ
- spring boot整合jooqSpring Boot
- spring與redis整合SpringRedis
- Spring Boot整合SocketSpring Boot
- Spring整合Mybatis plusSpringMyBatis