通知类。
代码结构。
// pom.xml
<?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>org.example</groupId>
<artifactId>text1</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring常用依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
// User.java
@Data
public class User {
}
// IUserDao.java
public interface IUserDao {
void show();
int addUser(User user);
int updateUser(User user);
int delUser(Integer id);
}
// UserDaoImpl.java
public class UserDaoImpl implements IUserDao {
@Override
public void show() {
System.out.println("show");
}
@Override
public int addUser(User user) {
// int i = 10/0;
System.out.println("addUser\n");
return 0;
}
@Override
public int updateUser(User user) {
System.out.println("updateUser");
return 0;
}
@Override
public int delUser(Integer id) {
System.out.println("delUser");
return 0;
}
}
// IUserService.java
public interface IUserService {
void show();
int addUser(User user);
int updateUser(User user);
int delUser(Integer id);
}
// UserServiceImpl.java
@Data
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
@Override
public void show() {
userDao.show();
}
@Override
public int addUser(User user) {
return userDao.addUser(user);
}
@Override
public int updateUser(User user) {
return userDao.updateUser(user);
}
@Override
public int delUser(Integer id) {
return userDao.delUser(id);
}
}
// MyBefore.java
public class MyBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("方法名:" + method.getName());
System.out.println("参数:" + Arrays.toString(objects));
System.out.println("目标名:" + o.getClass().getSimpleName());
System.out.println("前置增强\n");
}
}
// MyAfter.java
public class MyAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("方法返回值: "+o);
System.out.println("方法名: "+ method.getName());
System.out.println("参数: "+ Arrays.toString(objects));
System.out.println("目标名: "+ o1.getClass().getSimpleName());
System.out.println("后置增强\n");
}
}
// MyInterceptor.java
public class MyInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕增强前\n");
// 核心方法 放行
Object proceed = methodInvocation.proceed();
System.out.println("环绕增强后\n");
return proceed;
}
}
// MyException.java
// 异常通知
public class MyException implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("出错啦..");
}
}
// application.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"
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.xsd
">
<bean id="userDao" class="com.baidu.day.text.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.baidu.day.text.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- aop 配置增强类 -->
<bean id="myBefore" class="com.baidu.day.text.advice.MyBefore"></bean>
<bean id="myAfter" class="com.baidu.day.text.advice.MyAfter"></bean>
<bean id="myException" class="com.baidu.day.text.advice.MyException"></bean>
<bean id="myInterception" class="com.baidu.day.text.advice.MyInterceptor"></bean>
<aop:config>
<aop:pointcut id="myBeforePointCut" expression="execution(* com.baidu.day.text.service.IUserService.addUser(..))"/>
<aop:pointcut id="myAfterPointCut" expression="execution(* com.baidu.day.text.service.impl.UserServiceImpl.addUser(..))"/>
<aop:advisor advice-ref="myException" pointcut="execution(* com.baidu.day.text.service.impl.UserServiceImpl.addUser(..))"></aop:advisor>
<aop:advisor advice-ref="myInterception" pointcut="execution(* com.baidu.day.text.service.impl.UserServiceImpl.addUser(..))"></aop:advisor>
<aop:advisor advice-ref="myBefore" pointcut-ref="myBeforePointCut"></aop:advisor>
<aop:advisor advice-ref="myAfter" pointcut-ref="myAfterPointCut"></aop:advisor>
</aop:config>
</beans>
匹配通配切入点。
匹配固定包名方法名
execution(* com.baidu.day.text.service.impl.UserServiceImpl.addUser(..))
匹配固定返回类
execution(com.baidu.day.text.entity.User *(..))
匹配固定参数
execution(* *(com.baidu.day.text.entity.User))
匹配包名、子包名
execution(* com.baidu.day.text.service..*.*(..))
匹配包名
execution(* com.baidu.day.text.service.*.*(..))
// 测试
@Test
public void addUser() {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
IUserService userService = (IUserService) ac.getBean("userService");
userService.addUser(null);
}
// 打印
环绕增强前
方法名:addUser
参数:[null]
目标名:UserServiceImpl
前置增强
addUser
方法返回值: 0
方法名: addUser
参数: [null]
目标名: UserServiceImpl
后置增强
环绕增强后
Spring + MyBatis。
代码结构。
// pom.xml
<?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>org.example</groupId>
<artifactId>text2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>5.1.10.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.8</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- jackjar jackson jar版本要和webMVC的版本一一对应 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>quartz</groupId>
<artifactId>quartz</artifactId>
<version>1.5.1</version>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<!-- 生成 war 的包名设置 -->
<!-- <finalName>xx.xx</finalName>-->
<resources>
<!-- 可关联的资源文件 -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
// jdbc.properties
jdbc.username=root
jdbc.password=Liu01234
jdbc.url=jdbc:mysql://localhost:3306/mydb1?characterEncoding=utf-8
jdbc.driver=com.mysql.jdbc.Driver
#<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计-->
filters=stat
#<!-- 配置初始化大小 -->
initialSize=6
#<!-- 配置初始化最大连接数 -->
maxActive=20
#<!-- 配置初始化最小连接数 -->
minIdle=3
#<!-- 配置获取连接等待超时的时间,1分钟单位毫秒 -->
maxWait=60000
#<!-- 检测连接是否有效的SQL -->
validationQuery=SELECT ‘x‘
#<!-- 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效 -->
testWhileIdle=true
#<!-- 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 -->
testOnBorrow=false
#<!-- 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 -->
testOnReturn=false
#<!-- 启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true -->
maxPoolPreparedStatementPerConnectionSize=20
#<!-- 对于长时间不使用的连接强制关闭 -->
removeAbandoned=true
#<!-- 超过30秒的空闲连接就可以被关闭了,单位是秒 -->
removeAbandonedTimeout=30
#<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
timeBetweenEvictionRunsMillis=10000
#<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
minEvictableIdleTimeMillis=30000
// Emp.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private double comm;
private Integer deptno;
}
// IEmpMapper.java
public interface IEmpMapper {
List<Emp> getAll();
int addEmp(Emp e);
}
// IEmpService.java
public interface IEmpService {
List<Emp> getAll();
int addEmp(Emp e);
}
// EmpServiceImpl.java
@Data
public class EmpServiceImpl implements IEmpService {
private IEmpMapper empMapper;
@Override
public List<Emp> getAll() {
return empMapper.getAll();
}
@Override
public int addEmp(Emp e) {
int tag = empMapper.addEmp(e);
// 运行时异常
int i = 10/0;
return tag;
}
}
// EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.baidu.day.text.dao.IEmpMapper">
<insert id="addEmp" parameterType="emp">
insert into emp(ename, job, mgr, sal, hiredate, comm, deptno)
values(#{ename},#{job},#{mgr},#{sal},#{hiredate},#{comm},#{deptno})
</insert>
<select id="getAll" resultType="emp">
select * from emp
</select>
</mapper>
// spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- 数据库 -->
<context:property-placeholder location="classpath*:jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 别名 -->
<property name="typeAliasesPackage" value="com.baidu.day.text.entity" />
<!-- <property name="mapperLocations">-->
<!-- <array>-->
<!-- <value>classpath*:com/baidu/day/text/mapper/*.xml</value>-->
<!-- </array>-->
<!-- </property>-->
<!-- 读取 mapper.xml 文件 -->
<property name="mapperLocations" value="classpath*:com/baidu/day/text/mapper/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- mapper 接口包位置 bean name 首字母小写, IEmpMapper, i开头好像不用小写 -->
<property name="basePackage" value="com.baidu.day.text.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<bean id="empService" class="com.baidu.day.text.service.impl.EmpServiceImpl">
<property name="empMapper" ref="IEmpMapper" />
</bean>
<!-- 事务 -->
<!-- 配置事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 事务声明 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- timeout 超时时间;rollback-for,碰到什么样的报错回滚;propagation,事务隔离级别; -->
<!-- <tx:method name="addEmp" propagation="REQUIRED" rollback-for="Exception" timeout="60"/>-->
<tx:method name="show*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
<!-- <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />-->
</tx:attributes>
</tx:advice>
<!-- 事务部署 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.baidu.day.text.service..*.*(..))"></aop:advisor>
</aop:config>
</beans>
// 测试
@Test
public void getAll() {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
IEmpService empService = (IEmpService)ac.getBean("empService");
List<Emp> all = empService.getAll();
for (Emp emp : all) {
System.out.println(emp);
}
}
@Test
public void addEmp() {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
IEmpService empService = (IEmpService)ac.getBean("empService");
Emp emp = new Emp();
emp.setEname("张三");
emp.setJob("程序员");
emp.setHiredate(new Date());
emp.setDeptno(10);
emp.setComm(33.0);
emp.setMgr(1);
emp.setSal(22.0);
int i = empService.addEmp(emp);
System.out.println(i);
}
<tx:method,事务属性。
isolation,隔离级别。级别越高,多事务并发时,越安全,并发越差。
default,采用数据库的默认的设置。
read-uncommited,读未提交。
read-commited,读提交,Oracle数据库默认的隔离级别。
repeatable-read,可重复读,MySQL 数据库默认的隔离级别。
serialized-read,序列化读,级别最高。
事务并发时的安全问题。
脏读,一个事务读取到另一个事务还未提交的数据,大于等于 read-commited 可防止。
不可重复读,一个事务内多次读取一行数据的相同内容,其结果不一致,大于等于 repeatable-read 可防止。
幻影读,一个事务内多次读取一张表中的相同内容,其结果不一致,serialized-read 可防止。
propagation,传播行为。
当涉及到事务嵌套(Service调用Service)时,可以设置。
SUPPORTS,不存在外部事务,则不开启新事务;存在外部事务,则合并到外部事务中。适合查询。
REQUIRED,不存在外部事务,则开启新事务;存在外部事务,则合并到外部事务中。 默认值,适合增删改。