一、 MVC三层架构
Model
- 业务处理:业务逻辑(Service)
- 数据持久层:CRUD(Dao)
View
- 展示数据
- 提供链接发起Service请求(a、form、img…)
Controller
- 接收用户的请求(req:请求参数、Session信息)
- 交给业务层处理对应的代码
- 控制视图的跳转
登陆---->接受用户登陆请求---->处理用户请求(获取用户登陆参数:username、password)---->交给业务层处理登陆业务(判断用户名是否正确)---->Dao层查询用户名和密码是否正确---->数据库
过滤器(Filter)
步骤:
- maven导包
- 实现javax.servlet的Filter接口,重新特定方法
- 配置web.xml
注意:
1.过滤中的所有代吗,在过滤特定请求的时候都会执行
2、必须要让过滤器继续通行
chain.doFilter(request,response);
案例:设置两条路径,/filter/hello_filter以及/hello_filter,通过过滤器实现/filter/*的路径设置编码格式。最终显示:/filter/hello_filter正常输出中文格式的“你好世界!”,/hello_filter输出乱码
//展示类
public class FilterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("<h1>世界,你好!</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Filter类,注意导包Filter为javax.servlet包下的Filter
public class FilterTest implements Filter {
//初始化在系统启动时就加载
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter init");
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//设置编码格式操作
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=utf-8");
System.out.println("Filter doFilter Before");
//正确执行过滤器,必须加此行,不然会一直卡死不往下执行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter doFilter After");
}
//销毁在系统关闭时销毁
public void destroy() {
System.out.println("Filter destroy");
}
}
web.xml,配置servlet和filter:
/filter/hello_filter和/hello_filter都可以进入展示类
filter配置地址前缀为/filter的才可进入
<servlet>
<servlet-name>FilterIndex</servlet-name>
<servlet-class>com.zzz.filter.FilterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FilterIndex</servlet-name>
<url-pattern>/filter/hello_filter</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>FilterIndex</servlet-name>
<url-pattern>/hello_filter</url-pattern>
</servlet-mapping>
<filter>
<filter-name>FilterTest</filter-name>
<filter-class>com.zzz.filter.FilterTest</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterTest</filter-name>
<url-pattern>/filter/*</url-pattern>
</filter-mapping>
JDBC复习
常用接口
(1) Driver 接口:加载驱动程序。
(2) DriverManager 类:装人所需的 JDBC 驱动程序,编程时调用它的方法来创建连接。
(3) Connection 接口:编程时使用该类对象创建 Statement 对象。
(4) Statement 接口:编程时使用该类对象得到 ResultSet 对象。
(5) ResultSet 类:负责保存 Statement 执行后所产生的查询结果。
连接数据库
- 提前创建好数据库
CREATE DATABASE db1;
USE db1;
CREATE TABLE `user`(
`id` INT,
`name` VARCHAR(30)
);
INSERT INTO `user` VALUES (1,'张一'),(2,'张二'),(3,'张三'),(4,'张四'),(5,'张五');
- 导包
- 连接Mysql
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
Connection com = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "123456");
Statement stat = com.createStatement();
// 执行 增删改查 (DML)语句用 int executeUpdate(Sting sql);
// 执行 DQL 语句 ResultSet executeQuery(String sql);
String sql = "SELECT * FROM user";
ResultSet rs = stat.executeQuery(sql);
while (rs.next()){
System.out.println(rs.getInt("id") + "\t" + rs.getString("name"));
}
stat.close();
com.close();
JDBC 预编译
JDBC事务
- 开启事务 void setAutoCommit(boolean autoCommit)
- 提交事务 void commit() 使自上次提交/回滚以来所做的所有更改为永久更改,并释放此Connection对象当前持有的所有数据库锁。
- 回滚事务 void rollback() 撤销当前事务中所做的更改,并释放此Connection对象当前持有的所有数据库锁
try{
connection.setAutoCommit(false);//设置为false,开启事务
...sql语句
connection.commit();//以上两条SQL都执行成功就提交事务。
}catch(){
connection.rollback();
}
二、Spring
1、优点
- Spring是一个轻量级的框架 , 非侵入式的 (不会破坏原有程序,甚至简化原有代码)
- 控制反转 IoC , 面向切面 Aop
- 支持 事务
一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
2、IOC
参考:
https://blog.csdn.net/weixin_45842494/article/details/122772824?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-12-122772824-null-null.nonecase&utm_term=Spring学习笔记&spm=1018.2226.3001.4450
3、applicationContext
https://blog.csdn.net/weixin_45842494/article/details/122772913?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-11-122772913-null-null.nonecase&utm_term=Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0&spm=1018.2226.3001.4450
4、依赖注入(DI)
https://blog.csdn.net/weixin_45842494/article/details/122775544?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-9-122775544-null-null.nonecase&utm_term=Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0&spm=1018.2226.3001.4450
5、Bean的作用域
https://blog.csdn.net/weixin_45842494/article/details/122776494?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-8-122776494-null-null.nonecase&utm_term=Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0&spm=1018.2226.3001.4450
6、Spring自动装配
https://blog.csdn.net/weixin_45842494/article/details/122777536?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-7-122777536-null-null.nonecase&utm_term=Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0&spm=1018.2226.3001.4450
7. Spring使用注解开发
https://blog.csdn.net/weixin_45842494/article/details/122778659?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171930621116800227431608%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171930621116800227431608&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-6-122778659-null-null.nonecase&utm_term=Spring%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0&spm=1018.2226.3001.4450
@Component的三个衍生注解
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,目前使用哪一个功能都一样。
- @Controller:web层
- @Service:service层
- @Repository:dao层
以上这些注解,功能一样,就相当于将这个类交给Spring管理装配了!
前面写了指定注解扫描包
<context:component-scan base-package="com.xxc.pojo"/>
那如果使用了衍生注解,这些注解所在类并不完全在pojo下,这个时候,我们可以扩大指定注解扫描包的作用范围。
<context:component-scan base-package="com.xxc"/>
8、基于Java类进行配置
- 在User类上添加@Component注解,表示这个类标注为Spring的一个组件,放到容器中
- 新建一个config配置包,编写一个MyConfig配置类
- @Configuration 注解,代表这是一个配置类。
- 同时在user方法上注册@Bean
- 这个方法的返回值就是Bean的class,方法名就是bean的id。
@Configuration // 代表这是一个配置类
public class MyConfig {
@Bean // 注册一个bean,这里的返回值就是Bean的类型,方法名就是bean的id。
public User user(){
return new User();
}
}
- 测试
这里需要new AnnotationConfigApplicationContext。之前都是CPX。这里用获取注解的Context。
getBean(“user”, User.class)其实就是获取方法名
public class MyTest {
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
User user = applicationContext.getBean("user", User.class);
System.out.println(user.getName());
}
}
9、代理模式
AOP的底层机制就是动态代理模式
分类:
- 静态代理
- 动态代理
静态代理
静态代理代理的是真实对象
静态代理角色分析
- 抽象角色 : 一般使用接口或者抽象类来实现
- 真实角色 : 被代理的角色
- 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作
- 客户 : 使用代理角色来进行一些操作
代码实现
Rent.java 租房。即抽象角色
// 抽象角色,租房
public interface Rent {
public void rent();
}
Host.java 房东。真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
Proxy.java 代理角色。内置private Host host;房东属性
//代理角色:中介
public class Proxy implements Rent {
private Host host; // 中介代理的是房东,将房东作为属性
public Proxy() {}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
}
// 看房
public void seeHouse(){
System.out.println("带客户看房子。");
}
// 收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client.java 客户
public class Client {
public static void main(String[] args) {
// 房东要出租房
Host host = new Host();
// 中介帮助房东
Proxy proxy = new Proxy(host);
// 客户找中介
proxy.rent();
}
}
结果:
分析:在这个过程中,你直接接触的是中介,但是你依然通过中介租到了房东的房子。这就是所谓的代理模式。对于房东来说很纯粹,只有租出房子,而中介可以附加一些额外的操作,比如带客户看房,收中介费等等。
静态代理的优缺点
优点
- 可以使得我们的真实角色更加纯粹,不再去关注一些公共的事情。
- 公共的业务由代理来完成,实现了业务的分工。
- 公共业务发生扩展时变得更加集中和方便。
缺点
- 一个真实的角色就会产生一个代理角色;代码量翻倍,开发效率低
- 我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !
静态代理再理解
- 创建一个抽象角色,增删改查!
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
- 我们需要一个真实对象来完成这些增删改查操作
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("add了一个用户");
}
@Override
public void delete() {
System.out.println("delete了一个用户");
}
@Override
public void update() {
System.out.println("update了一个用户");
}
@Override
public void query() {
System.out.println("query了一个用户");
}
}
- 需求来了,现在我们需要增加一个日志功能,怎么实现?
- 思路1 :在实现类上增加代码 【麻烦!】
- 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
- 设置一个代理类来处理日志! 代理角色
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
public void log(String str){
System.out.println("打印了"+str+"的日志");
}
}
- 测试访问类:
运用代理模式,新建一个类,实现接口,代理真实对象。
这里使用setUserService使用了控制反转的思想,将调用权给用户。
public class Client {
public static void main(String[] args) {
//真实业务
UserServiceImpl userService = new UserServiceImpl();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想。
动态代理
底层是反射
代理的是接口(静态代理代理的是真实对象)
- 动态代理的角色和静态代理的一样。
- 动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理–cglib
- 现在用的比较多的是 javasist 来生成动态代理
- 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!
JDK的动态代理需要了解两个类
nvocationHandler (调用处理程序)和 Proxy(动态创建代理对象)
代码实现
抽象角色和真实角色与之前的一样!
//抽象角色:租房
public interface Rent {
public void rent();
}
//真实角色: 房东,房东要出租房子
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
ProxyInvocationHandler.java代理角色
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rent, args);
fare();
return result;
}
// 看房
public void seeHouse(){
System.out.println("带房客看房");
}
// 收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client.java
public class Client {
public static void main(String[] args) {
// 真实角色
Host host = new Host();
// 代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); // 将真实角色放置进去
Rent proxy = (Rent) pih.getProxy(); // 动态生成对应的代理类
proxy.rent();
}
}
核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!
动态代理深化理解
我们来使用动态代理实现代理我们后面写的UserService!
我们也可以编写一个通用的动态代理实现的类(相当于工具类)!所有的代理对象设置为Object即可!
ProxyInvocationHandler .java
//此时有需求:添加日志
public class ProxyInvocationHandler implements InvocationHandler {
private Object object;
public void setObject(Object object) {
this.object = object;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object invoke = method.invoke(object, args);
return invoke;
}
//此时有需求:添加日志
public void log(String str){
System.out.println("执行了"+str+"方法");
}
}
Client.java
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setObject(userService);
UserService proxy = (UserService) proxyInvocationHandler.getProxy();
proxy.add();
}
}
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
- 可以使得我们的真实角色更加纯粹,不再去关注一些公共的事情 .
- 公共的业务由代理来完成,实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口!
10、AOP
使用Spring实现AOP
- 通过 Spring API 实现
实现接口MethodBeforeAdvice (前置)、AfterReturningAdvice (后置)。最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束
public class BeforeLog implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
<?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-->
<bean id="userService" class="com.xxc.service.UserServiceImpl"/>
<bean id="after" class="com.xxc.log.AfterLog"/>
<bean id="before" class="com.xxc.log.BeforeLog"/>
<!--aop的配置-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.xxc.service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="before" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="after" pointcut-ref="pointcut"/>
</aop:config>
</beans>
- 自定义类来实现
自定义一个类,并在配置文件中配置
public class DiyPointcut {
public void before(){
System.out.println("============在方法执行前执行=============");
}
public void after(){
System.out.println("===========在方法执行后执行==============");
}
}
<?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-->
<bean id="userService" class="com.xxc.service.UserServiceImpl"/>
<bean id="diy" class="com.xxc.config.DiyPointcut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diyPonitcut" expression="execution(* com.xxc.service.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="diyPonitcut" method="before"/>
<aop:after pointcut-ref="diyPonitcut" method="after"/>
</aop:aspect>
</aop:config>
</beans>
- 使用注解实现
编写一个注解实现的增强类,标注@Aspect、@Before(“execution(* com.xxc.service.UserServiceImpl.*(…))”)、@After、 @Around。最后配置文件中配置
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.xxc.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.xxc.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.xxc.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
<?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="userService" class="com.xxc.service.UserServiceImpl"/>
<bean id="annotationPointcut" class="com.xxc.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
</beans>
11、整合Mybatis
https://blog.csdn.net/weixin_45842494/article/details/122793998
12、声明式事务
AOP,交给容器管理
当执行一段代码:先新增一条数据,再删除另一条数据,最后查询所有数据,此时删除中代码写错了。
如果没有事务则会出现报错提示,数据新增成功,删除失败。是有问题的,应该保证ACID原则,要么都成功要么都失败。
以前的事务都是手动开启、手动提交的,非常麻烦。
现在Spring给我们提供了事务管理,我们只需要配置即可
声明式事务的配置:
- 头文件导入tx:
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
- 配置事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
- 配置事务通知
在开发中,我们只需要配置最后的<tx:method name=“*” propagation=“REQUIRED”/>即可,这个就表示给所有方法添加了事务。
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
- 配置aop织入
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.xxc.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
此时的结果: 还是会报异常,但是数据并没有插入,达到了我们想要的效果。
还有一种编程式事务,其原理就是加上trycatch,报错调用回滚