Spring
Spring整合MyBatis
配置数据源
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}"/>
<!--配置获取连接等待超时的时间-->
<property name="maxWait" value="60000"/>
<!--配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--配置一个连接在池中最小生存的时间,单位是毫秒-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>
</beans>
3.Druid连接池可选参数
<!--配置初始化大小,最小,最大-->
<property name="initialSize" value="${jdbc.init}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!--配置获取连接等待超时的时间-->
<property name="maxWait" value="60000"/>
<!--配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--配置一个连接在池中最小生存的时间,单位是毫秒-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
4.Druid监控中心
5.测试监控中心
整合MyBatis
1.导入依赖
<!--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驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
2.配置SqlSessionFactory
<!--生产SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入连接池-->
<property name="dataSource" ref="dataSource"/>
<!--注册mapper文件信息,如果映射文件和dao接口 同包且同名,则此配置可以省略-->
<property name="mapperLocations">
<list>
<value>classpath:cn/ozl/dao/*.xml</value>
</list>
</property>
<!--为mapper文件中的实体定义缺省包路径-->
<property name="typeAliasesPackage" value="cn.ozl.entity"></property>
</bean>
3.配置MapperScannerConfigurer
管理DAO实现类的创建,并创建DAO对象,存入工厂管理
1.扫描所有DAO接口,去构建DAO实现
2.将DAO实现存入工厂管理
3.DAO实现对象在工厂的id是:“首字母小写的-接口额类名”,例如UserDao=》userDao
<bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.ozl.dao"/>
<!--只有一个SqlSessionFactory的bean可以省略-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
4.配置Service
<bean id="userService" class="cn.ozl.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
事务
applicationContext.xml
<!--引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务通知-->
<tx:advice id="txManager" transaction-manager="tx">
<!--事务属性-->
<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>
<!--编织 声明式事务控制-->
<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 事务");
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("test 事务!!");
}
}
return integer;
}
}
test测试
@Test
public void testtx(){
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.deleteUser(1002);
}
1.配置DataSourceTransactionManager
事务管理器,其中持有DataSoure,可以控制事务功能(rollback,commit等)
<!--引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
注意:DataSourceTransactionManager和SqlSessionFactoryBean要注入同一个DataSource的bean,否则事务控制会失败
2.配置事务通知
基于事务管理,进一步控制,生成一个额外的功能:advice
此Advice可以切入任何的需要事务的方法,通过事务管理器为方法控制事务
<!--事务通知-->
<tx:advice id="txManager" transaction-manager="tx">
<!--事务属性-->
<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.事务属性
3.1隔离级别
isolation
1.default (默认值)(采取数据库的默认设置)(建议)
2.read-uncommited 读未提交
3.read-commited 读提交
4.repeatable-read 可重复读
5.serialized-read 序列化读
隔离级别由低到高:read-uncommited<read-commited<repeatable-read<serialized-read
安全性:级别越高,多事务并发时,越安全,因为共享的数据越来越少,事务彼此之间干扰减少
并发性:级别越高,多事务并发时,并发越差,因为共享的数据越来越少,事务间阻塞情况增多
事务并发时的安全问题
1.脏读:一个事务读取到另一个事务还未提交的数据
大于read-uncommited可防止
2.不可重复读:一个事务内多次读取一行数据的相同内容,其结果不一致
大于read-commited可防止
3,幻读:一个事务内多次读取一张表中相同的内容,其结果不一致
大于repeatale-read可防止
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
3.2传播行为
propagation
当涉及到事务的嵌套(Service调用Service)中,可能存在的问题
1.SUPPORTS=不存在外部事务,则不开启新的事务,存在外部事务,则合并到外部事务中(适合查询)
2.REQUIRED=不存在外部事务,则开启事务,存在外部事务,则合并到外部事务中(默认值)(适合增删改)
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
3.3读写性
readonly
1.true:只读,可提交查询效率(适合查询)
2.false:可读可写 (默认值)(适合增删改)
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
3.4事务超时
timeout
当事务所需操作的数据被其他事务占用,则等待
1.100:自定义等待时间100(秒)
2.-1:由数据库指定等待时间,默认值(建议)
<!--<tx:method name="insertUser" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" rollback-for="Exception"/>-->
3.5事务回滚
rollback-for
1.如果事务中抛出 RuntimeException,则自动回滚
2.如果事务中抛出 CheckException(非运行时异常 Exception),不会自动回滚,而是默认提交事务
3.处理方案:将CheckException转换成RuntimeException上抛,或设置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 事务");
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("test 事务!!");
}
}
return integer;
}
4.编织
将管理的advice切入需要事务的业务中
<!--编织 声明式事务控制-->
<aop:config>
<aop:pointcut id="pzl_tx" expression="execution(* cn.ozl.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="txManager" pointcut-ref="pzl_tx"/>
</aop:config>