配置數(shù)據(jù)源
1.引入jdbc.properties配置文件
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.init=1
jdbc.minIdle=1
jdbc.maxActive=3
2.整合Spring配置文件和properties配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context.spring-context.xsd">
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!--基本配置-->
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--配置初始化大小,最小,最大-->
<property name="initialSize" value="${jdbc.init}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!--配置獲取連接等待超時(shí)的時(shí)間-->
<property name="maxWait" value="60000"/>
<!--配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>
</beans>
3.Druid連接池可選參數(shù)
<!--配置初始化大小,最小,最大-->
<property name="initialSize" value="${jdbc.init}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!--配置獲取連接等待超時(shí)的時(shí)間-->
<property name="maxWait" value="60000"/>
<!--配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
4.Druid監(jiān)控中心
web.xml
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
5.測(cè)試監(jiān)控中心
配置tomcat,并訪問(wèn)protocol://ip:port/project/druid/index.html
整合MyBatis
1.導(dǎo)入依賴
<!--Spring整合MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql驅(qū)動(dòng)-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
2.配置SqlSessionFactory
<!--生產(chǎn)SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入連接池-->
<property name="dataSource" ref="dataSource"/>
<!--注冊(cè)mapper文件信息,如果映射文件和dao接口 同包且同名,則此配置可以省略-->
<property name="mapperLocations">
<list>
<value>classpath:cn/ozl/dao/*.xml</value>
</list>
</property>
<!--為mapper文件中的實(shí)體定義缺省包路徑-->
<property name="typeAliasesPackage" value="cn.ozl.entity"></property>
</bean>
3.配置MapperScannerConfigurer
管理DAO實(shí)現(xiàn)類的創(chuàng)建,并創(chuàng)建DAO對(duì)象,存入工廠管理
- 掃描所有DAO接口,去構(gòu)建DAO實(shí)現(xiàn)
- 將DAO實(shí)現(xiàn)存入工廠管理
- DAO實(shí)現(xiàn)對(duì)象在工廠的id是:“首字母小寫(xiě)的接口類名”,例如UserDao=>userDao
<bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.ozl.dao"/>
<!--只有一個(gè)SqlSessionFactory的bean可以省略-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
4.配置Service
<bean id="userService" class="cn.ozl.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
事務(wù)
applicationContext.xml
<!--引入一個(gè)事務(wù)管理器,其中依賴DataSource,借以獲得連接,進(jìn)而控制事務(wù)邏輯-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事務(wù)通知-->
<tx:advice id="txManager" transaction-manager="tx">
<!--事務(wù)屬性-->
<tx:attributes>
<!--<tx:method name="queryUser" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1" rollback-for="Exception"/>-->
<tx:method name="queryUser" propagation="SUPPORTS" />
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
<tx:method name="*User" rollback-for="Exception"/>
<!--剩余的所有方法-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--編織 聲明式事務(wù)控制-->
<aop:config>
<aop:pointcut id="pzl_tx" expression="execution(* cn.ozl.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="txManager" pointcut-ref="pzl_tx"/>
</aop:config>
UserServiceImpl
public class UserServiceImpl implements UserService{
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public List<User> queryUsers() {
return userDao.queryUsers();
}
public void insertUser(User user) {
userDao.insertUser(user);
}
public void updateUser(User user) {
userDao.updateUser(user);
}
public Integer deleteUser(Integer id) {
Integer integer=userDao.deleteUser(id);
System.out.println(integer);
if (1==1){
try {
throw new SQLException("test 事務(wù)");
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("test 事務(wù)!!");
}
}
return integer;
}
}
test測(cè)試
@Test
public void testtx(){
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.deleteUser(1002);
}
1.配置DataSourceTransactionManager
事務(wù)管理器,其中持有DataSoure,可以控制事務(wù)功能(rollback,commit等)
<!--引入一個(gè)事務(wù)管理器,其中依賴DataSource,借以獲得連接,進(jìn)而控制事務(wù)邏輯-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
注意:DataSourceTransactionManager和SqlSessionFactoryBean要注入同一個(gè)DataSource的bean,否則事務(wù)控制會(huì)失敗
2.配置事務(wù)通知
基于事務(wù)管理,進(jìn)一步控制,生成一個(gè)額外的功能:advice
此Advice可以切入任何的需要事務(wù)的方法,通過(guò)事務(wù)管理器為方法控制事務(wù)
<!--事務(wù)通知-->
<tx:advice id="txManager" transaction-manager="tx">
<!--事務(wù)屬性-->
<tx:attributes>
<!--<tx:method name="queryUser" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1" rollback-for="Exception"/>-->
<tx:method name="queryUser" propagation="SUPPORTS" />
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
<tx:method name="*User" rollback-for="Exception"/>
<!--剩余的所有方法-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
3.事務(wù)屬性
3.1隔離級(jí)別
isolation
- default (默認(rèn)值)(采取數(shù)據(jù)庫(kù)的默認(rèn)設(shè)置)(建議)
- read-uncommited 讀未提交
- read-commited 讀提交
- repeatable-read 可重復(fù)讀
- serialized-read 序列化讀
隔離級(jí)別由低到高:read-uncommited<read-commited<repeatable-read<serialized-read
安全性:級(jí)別越高,多事務(wù)并發(fā)時(shí),越安全,因?yàn)楣蚕淼臄?shù)據(jù)越來(lái)越少,事務(wù)彼此之間干擾減少
并發(fā)性:級(jí)別越高,多事務(wù)并發(fā)時(shí),并發(fā)越差,因?yàn)楣蚕淼臄?shù)據(jù)越來(lái)越少,事務(wù)間阻塞情況增多
事務(wù)并發(fā)時(shí)的安全問(wèn)題
- 臟讀:一個(gè)事務(wù)讀取到另一個(gè)事務(wù)還未提交的數(shù)據(jù)
大于read-uncommited可防止- 不可重復(fù)讀:一個(gè)事務(wù)內(nèi)多次讀取一行數(shù)據(jù)的相同內(nèi)容,其結(jié)果不一致
大于read-commited可防止- 幻讀:一個(gè)事務(wù)內(nèi)多次讀取一張表中相同的內(nèi)容,其結(jié)果不一致
大于repeatale-read可防止
<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>
3.2傳播行為
propagation
當(dāng)涉及到事務(wù)的嵌套(Service調(diào)用Service)中,可能存在的問(wèn)題
SUPPORTS=不存在外部事務(wù),則不開(kāi)啟新的事務(wù),存在外部事務(wù),則合并到外部事務(wù)中(適合查詢)REQUIRED=不存在外部事務(wù),則開(kāi)啟事務(wù),存在外部事務(wù),則合并到外部事務(wù)中(默認(rèn)值)(適合增刪改)
<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>
3.3讀寫(xiě)性
readonly
- true:只讀,可提交查詢效率(適合查詢)
- false:可讀可寫(xiě) (默認(rèn)值)(適合增刪改)
<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>
3.4事務(wù)超時(shí)
timeout
當(dāng)事務(wù)所需操作的數(shù)據(jù)被其他事務(wù)占用,則等待
- 100:自定義等待時(shí)間100(秒)
- -1:由數(shù)據(jù)庫(kù)指定等待時(shí)間,默認(rèn)值(建議)
<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>
3.5事務(wù)回滾
rollback-for
- 如果事務(wù)中拋出 RuntimeException,則自動(dòng)回滾
- 如果事務(wù)中拋出 CheckException(非運(yùn)行時(shí)異常 Exception),不會(huì)自動(dòng)回滾,而是默認(rèn)提交事務(wù)
- 處理方案:將CheckException轉(zhuǎn)換成RuntimeException上拋,或設(shè)置rollback-for=“Exception”
<tx:method name="*User" rollback-for="Exception"/>
public Integer deleteUser(Integer id) {
Integer integer=userDao.deleteUser(id);
System.out.println(integer);
if (1==1){
try {
throw new SQLException("test 事務(wù)");
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("test 事務(wù)!!");
}
}
return integer;
}
4.編織
將管理的advice切入需要事務(wù)的業(yè)務(wù)中
<!--編織 聲明式事務(wù)控制-->
<aop:config>
<aop:pointcut id="pzl_tx" expression="execution(* cn.ozl.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="txManager" pointcut-ref="pzl_tx"/>
</aop:config>