阿勒泰高端网站建设公司,黑客入侵网课,新手网络推广怎么干,搜索引擎和门户网站的区别系列文章目录
IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介
IDEWA项目实践——mybatis的一些基本原理以及案例
IDEA项目实践——动态SQL、关系映射、注解开发
IDEA项目实践——Spring框架简介#xff0c;以及IOC注解
IDEA项目实践—…系列文章目录
IDEA项目实践——创建Java项目以及创建Maven项目案例、使用数据库连接池创建项目简介
IDEWA项目实践——mybatis的一些基本原理以及案例
IDEA项目实践——动态SQL、关系映射、注解开发
IDEA项目实践——Spring框架简介以及IOC注解
IDEA项目实践——Spring当中的切面AOP
文章目录
系列文章目录
前言
一 Spring集成mybatis
1.1 MySQL创建数据库ssm新建表Student表
1.1 MySQL 创建数据库 ssm,新建表 Student
1.1.1 原JDBC建立连接形式的讲解
1指定数据源
2 工具类
1.1.2 创建Maven项目
1.2 maven 依赖 pom.xml
1.3 定义实体类 Student
1.4 定义 StudentDao 接口
1.5 定义映射文件 mapper
1.6 定义 Service 接口和实现类
1.7 定义 MyBatis 主配置文件
1.8 修改 Spring 配置文件
1 数据源的配置(掌握) 2 从属性文件读取数据库连接信息
3 注册 SqlSessionFactoryBean
4 定义 Mapper 扫描配置器 MapperScannerConfigurer
1.9 向 Service 注入接口名
1.10 Spring 配置文件全部配置
二 Spring 事务
2.1 Spring 的事务管理
2.2 Spring 事务管理 API
1 事务管理器接口(重点) A、 常用的两个实现类 B、Spring 的回滚方式(理解)
C、回顾错误与异常(理解)
2 事务定义接口
I、事务隔离级别常量
1脏读Dirty read
2不可重复读Nonrepeatable read
3幻读Phantom read
II、事务传播行为常量
a、 PROPAGATION_REQUIRED
b、PROPAGATION_SUPPORTS
c、 PROPAGATION_REQUIRES_NEW
III、事务默认超时时限常量【了解即可】
2.3 程序举例环境搭建
Step0创建数据库表
编辑 Step1: maven 依赖 pom.xml
Step2创建实体类
Step3定义 dao 接口
Step4定义 dao 接口对应的 sql 映射文件
Step5定义异常类
Step6定义 Service 接口
Step7定义 service 的实现类
Step8修改 Spring 配置文件内容 Step9定义测试类
2.4 使用 Spring 的事务注解管理事务(掌握)
实现注解的事务步骤
1. 声明事务管理器
2. 开启注解驱动 transaction-manager
3. 业务层 public 方法加入事务属性
第一句是需要有事务
此处事务回滚是发生库存不足和商品为空时的class
编辑
2.5 使用 AspectJ 的 AOP 配置管理事务(掌握)
Step1复制项目 Step2maven 依赖 pom.xml
Step3在容器中添加事务管理器
Step4配置事务通知
Step5配置增强器
Step6修改测试类 前言
本文主要介绍Spring集成mybatis以及spring当中的事务文章当中的案例仅供参考。 一 Spring集成mybatis
将MyBatis 与 Spring进行整合主要解决的问题就是将SqlSessionFactory对象交由Spring来管理。所以该整合只需要将SqlSessionFactory的对象生成器 将与与Spring进行整合主要解决的问题就是SqlSessionFactoryBean注册在Spring容器中再将其注入给Dao的实现类即可完成整合。
实现Spring与MyBatis的整合常用的方式:扫描的Mapper动态代理
Spring 像插线板一样mybatis框架是插头可以容易的组合到一起。插线板spring插上 mybatis两个框架就是一个整体。
1.1 MySQL创建数据库ssm新建表Student表 创建实体类student 1.1 MySQL 创建数据库 ssm,新建表 Student
1.1.1 原JDBC建立连接形式的讲解
1指定数据源
原来的jdbc形式的配置文件 指定数据源 2 工具类 mybatis与spring spring
1.1.2 创建Maven项目 1.2 maven 依赖 pom.xml
dependenciesdependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopetest/scope/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.11/version/dependency!-- Spring整合MyBatis的依赖 --dependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion2.1.0/version/dependency!-- --------------------- --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.29/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.2.8/version/dependency
/dependencies !--插件--
buildresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resource/resourcespluginsplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-compiler-plugin/artifactIdversion3.11.0/versionconfigurationsource1.8/sourcetarget1.8/target/configuration/plugin/plugins
/build
1.3 定义实体类 Student 创建学生的实体类 编辑代码如下
package com.ambow.pojo;import lombok.Data;Data
public class Student {private int id;private String name;private int age;
}1.4 定义 StudentDao 接口 此处选择接口写的时候没有截全
package com.ambow.dao;import com.ambow.pojo.Student;import java.util.List;public interface StudentDao {int insertStudent(Student student);int updateStudent(Student student);int deleteStudent(Student student);Student selectStudentById(int id);ListStudent selectAllStudents();
}1.5 定义映射文件 mapper
在 Dao 接口的包中创建 MyBatis 的映射文件 mapper命名与接口名相 同本例为 StudentDao.xml。mapper 中的 namespace 取值也为 Dao 接口 的全限定性名。
项目的路径在此处
编辑映射文件的代码
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd!--添加命名空间--
mapper namespacecom.ambow.dao.StudentDaoinsert idinsertStudentinsert into student values(null,#{name},#{age})/insertupdate idupdateStudentupdate student set name #{name},age #{age} where id #{id}/updatedelete iddeleteStudentdelete from student where id #{id}/deleteselect idselectStudentById resultTypecom.ambow.pojo.Studentselect * from student where id #{id}/selectselect idselectAllStudents resultTypecom.ambow.pojo.Studentselect * from student/select/mapper
1.6 定义 Service 接口和实现类
接口定义 package com.ambow.service;import com.ambow.pojo.Student;import java.util.List;public interface StudentService {int addStudent(Student student);int modifyStudent(Student student);int removeStudent(int id);Student findStudentById(int id);ListStudent findAllStudents();
}接口的实现类定义 自动生成接口的实现类 package com.ambow.service.impl;import com.ambow.dao.StudentDao;
import com.ambow.pojo.Student;
import com.ambow.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;Service(studentService)
public class StudentServiceImpl implements StudentService {//引入StudentDao的对象Autowiredprivate StudentDao studentDao;//Spring有set注入方法public void setStudentDao(StudentDao studentDao) {this.studentDao studentDao;}Overridepublic int addStudent(Student student) {return studentDao.insertStudent(student);}Overridepublic int modifyStudent(Student student) {return studentDao.updateStudent(student);}Overridepublic int removeStudent(Student student) {return 0;}Overridepublic int removeStudent(int id) {return studentDao.deleteStudent(id);}Overridepublic Student findStudentById(int id) {return studentDao.selectStudentById(id);}Overridepublic ListStudent findAllStudents() {return studentDao.selectAllStudents();}
}1.7 定义 MyBatis 主配置文件
在 src 下定义 MyBatis 的主配置文件命名为 mybatis.xml。
这里有两点需要注意
1主配置文件中不再需要数据源的配置了。因为数据源要交给 Spring 容器 来管理了。
2这里对 mapper 映射文件的注册使用标签即只需给出 mapper 映射文件所在的包即可。因为 mapper 的名称与 Dao 接口名相同 可以使用这种简单注册方式。这种方式的好处是若有多个映射文件这里的 配置也是不用改变的。当然也可使用原来的标签方式。 原先的environment数据源将交由Spring来管理 【代管】 mybatis-config.xml文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
configurationproperties resourcejdbc.properties/typeAliasespackage namecom.ambow.pojo//typeAliasesenvironments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/ssm?serverTimezoneUTC/property nameusername valueroot/property namepassword valueroot//dataSource/environment/environmentsmapperspackage name com.ambow.dao//mappers
/configuration
jdbc.properties文件
drivercom.mysql.cj.jdbc.Driver
urljdbc:mysql://localhost:3306/ssm?serverTimezoneUTC
usernameroot
passwordroot
可以先测试一下 测试类的代码:
package com.ambow.test;import com.ambow.dao.StudentDao;
import com.ambow.pojo.Student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class SMTest {Testpublic void test01() throws IOException {//先找到主配置文件String url mybatis-config.xml;//读取主配置文件InputStream inputStream Resources.getResourceAsStream(url);//输入流拿到SqlSessionFactory工厂对象SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);//再次拿到SqlSession对象SqlSession sqlSession sqlSessionFactory.openSession();//最后拿到StudentDao对象StudentDao studentDao ((SqlSession) sqlSession).getMapper(StudentDao.class);//拿到学生对象进行遍历ListStudent students studentDao.selectAllStudents();for (Student student : students) {System.out.println(student);}}
}等价于将原来的mybatis代码写一遍然后修改
1.8 修改 Spring 配置文件 整合把MyBatis中的核心对象放到Spring容器 1 数据源的配置(掌握)
使用 JDBC 模板首先需要配置好数据源数据源直接以 Bean 的形式配置 在 Spring 配置文件中。根据数据源的不同其配置方式不同
Druid 数据源 DruidDataSource Druid 是阿里的开源数据库连接池。是 Java 语言中最好的数据库连接 池。Druid 能够提供强大的监控和扩展功能。Druid 与其他数据库连接池的 最大区别是提供数据库的
官网GitHub - alibaba/druid: 阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品为监控而生的数据库连接池
使用地址Home · alibaba/druid Wiki · GitHub常见问题
配置连接池 Spring 配置文件 2 从属性文件读取数据库连接信息
为了便于维护可以将数据库连接信息写入到属性文件中使 Spring 配置 文件从中读取数据。
属性文件名称自定义但一般都是放在 src 下。 jdbc.drivercom.mysql.cj.jdbc.Driver
jdbc.urljdbc:mysql://localhost:3306/ssm?serverTimezoneUTC
jdbc.usernameroot
jdbc.passwordroot Spring 配置文件从属性文件中读取数据时需要在的 value 属性中使用${ }将在属性文件中定义的 key 括起来以引用指定属性的值。
该属性文件若要被 Spring 配置文件读取其必须在配置文件中进行注册。 使用context标签。
context:property-placeholder /方式(掌握)
该方式要求在 Spring 配置文件头部加入 spring-context.xsd 约束文件
context:property-placeholder /标签中有一个属性 location用于指定属 性文件的位置。 3 注册 SqlSessionFactoryBean 工厂类拿到工厂对象以及主配置文件 4 定义 Mapper 扫描配置器 MapperScannerConfigurer
Mapper 扫描配置器 MapperScannerConfigurer 会自动生成指定的基本 包中 mapper 的代理对象。该 Bean 无需设置 id 属性。basePackage 使用分 号或逗号设置多个包。 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd!--整合把MyBatis中的核心对象放到Spring容器--!--引入属性配置文件--context:property-placeholder locationclasspath:jdbc.properties /context:component-scan base-packagecom.ambow.service /!--1.DataSource--bean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName value${jdbc.driver} /property nameurl value${jdbc.url} /property nameusername value${jdbc.username} /property namepassword value${jdbc.password} //bean!--2.注册SqlSessionFactoryBean--bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource /!--起别名的也可以将其放在这里--property nametypeAliasesPackage valuecom.ambow.pojo /!--mapper映射文件的位置此处的value里面包之间需要使用/分割--property namemapperLocations valueclasspath:com/ambow/dao/*.xml //bean!--3.mapper的扫描配置器 - 生成mapper的代理对象--bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namesqlSessionFactoryBeanName valuesqlSessionFactory /property namebasePackage valuecom.ambow.dao //bean/beans
1.9 向 Service 注入接口名
向 Service 注入 Mapper 代理对象时需要注意由于通过 Mapper 扫描配置器 MapperScannerConfigurer 生成的 Mapper 代理对象没有名称所以在 向 Service 注入 Mapper 代理时无法通过名称注入。但可通过接口的简单类名注入因为生成的是这个 Dao 接口的对象。 补充的地方:
!--4.向service层注入Dao--
!-- bean idstudentService classcom.ambow.service.impl.StudentServiceImplproperty namestudentDao refstudentDao //bean--!--注入的过程--!--dataSource - SqlSessionFactoryBean - MapperScannerConfigurer(生成Dao代理对象) - studentService--1.10 Spring 配置文件全部配置 测试一下
Testpublic void test02() throws IOException {ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);StudentService studentService (StudentService) context.getBean(studentService);ListStudent allStudents studentService.findAllStudents();System.out.println(allStudents.size());for (Student student : allStudents) {System.out.println(student);}} 注意事项 前面的jdbc的配置文件里面需要加上jdbc.的前缀否则这个找到的是本机的username而不是mysql的用户名 此处可以看到拿到的并不是mysql的用户而是电脑主机的用户名。 再次压缩一下
原来的mybatis-config文件里面的内容可以整合一下
整合完之后删除mybatis-config文件 前面的第四部可以使用注解的方式来做 实际的开发环境当中。 //自定义的类就可以使用注解的方法来写注入 //非自定义的类就需要在配置文件里面注入 二 Spring 事务
2.1 Spring 的事务管理
事务原本是数据库中的概念在 Dao 层。但一般情况下需要将事务提升到业务层即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。
在 Spring 中通常可以通过以下两种方式来实现对事务的管理
1使用 Spring 的事务注解管理事务
2使用 AspectJ 的 AOP配置管理事务
2.2 Spring 事务管理 API
Spring 的事务管理主要用到两个事务相关的接口。
1 事务管理器接口(重点)
事务管理器是 PlatformTransactionManager 接口对象。
其主要用于完成事务的提交、回滚及获取事务的状态信息。
接口无法直接使用需要实现类实际使用的是下面的两个类 A、 常用的两个实现类
PlatformTransactionManager 接口有两个常用的实现类 DataSourceTransactionManager使用 JDBC 或 MyBatis 进行数据库操作时使用。 HibernateTransactionManager使用 Hibernate 进行持久化数据时使用。 B、Spring 的回滚方式(理解)
Spring 事务的默认回滚方式是发生运行时异常和 error 时回滚发生受查(编译)异常时提交。不过对于受查异常程序员也可以手工设置其回滚方式。
C、回顾错误与异常(理解) Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类 (或其子类之一)的实例时才能通过 Java 虚拟机或者 Java 的 throw 语句抛出。 Error是程序在运行过程中出现的无法处理的错误比如 OutOfMemoryError、ThreadDeath、NoSuchMethodError 等。当这些错误发生时程序是无法处理捕获或抛出的JVM 一般会终止线程。Exception程序在编译和运行时出现的另一类错误称之为异常它是 JVM 通知程序员的一种方式。通过这种方式让程序员知道已经或可能出现错误要求程序员对其进行处理。 异常分为运行时异常与受查异常。
运行时异常是 RuntimeException 类或其子类即只有在运行时才出现的异常。如NullPointerException、ArrayIndexOutOfBoundsException、 IllegalArgumentException 等均属于运行时异常。这些异常由JVM抛出在编译时不要求必须处理捕获或抛出。但只要代码编写足够仔细程序足够健壮运行时异常是可以避免的。【因此运行时异常也叫非受查异常编译器无法检查到需要程序员通过修改代码来解决】
受查异常也叫编译时异常即在代码编写时要求必须捕获或抛出的异常若不处理则无法通过编译。如 SQLException ClassNotFoundExceptionIOException 等都属于受查异常。
RuntimeException 及其子类以外的异常均属于受查异常。当然用户自定义的 Exception 的子类即用户自定义的异常也属受查异常。程序员在定义异常时只要未明确声明定义的为 RuntimeException 的子类那么定义的就是受查异常。 Ø 非检查异常(unckecked exception)Error 和 RuntimeException 以及他们的子类。javac在编译时不会提示和发现这样的异常不要求程序员必须处理这些异常。在运行阶段倘若发生Error则虚拟机几乎崩溃倘若发生RuntimeException若程序员没处理它则一直回溯向上抛给java虚拟机处理。当然如果程序员愿意的话也可以编写代码处理(使用try…catch…finally)这样的异常(但是通常情况下不会这样做。需要这样做的情况是比如搞数学运算的这个专业领域要处理ArithmeticException)。对于这些异常我们应该修正代码而不是去通过异常处理器处理。这种异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException错误的强制类型转换错误ClassCastException数组索引越界ArrayIndexOutOfBoundsException使用了空对象NullPointerException等等。 Ø 检查异常(checked exception)除了Error和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理要么用throws子句声明抛出它否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下而程序员无法干预用户如何使用他编写的程序于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。 发生运行时异常才会回滚 QA为什么添加事务管理器 答因为不同的技术管理事务的类不同比如 JDBCConnecton con.commit(); con.rollback();MyBatisSqlSession sqlSession.commit(); sqlSession.rollback();HibernateSession session.commit(); session.rollback(); 事务管理器用来生成相应技术的连接对象及执行语句。 不同框架提交事务是不同的 2 事务定义接口
事务定义接口 TransactionDefinition 中定义了事务描述相关的三类常量
事务隔离级别、事务传播行为、事务默认超时时限及对它们的操作。 I、事务隔离级别常量
定义了五个事务隔离级别常量(掌握)
在应用程序中多个事务并发运行操作相同的数据可能会引起脏读、不可重复读、幻读等问题。
1脏读Dirty read
第一个事务访问并改写了数据尚未提交事务这时第二个事务进来了读取了刚刚改写的数据如果这时第一个事务回滚了这样第二个事务读取到的数据就是无效的“脏数据”。
2不可重复读Nonrepeatable read
第一个事务在其生命周期内多次查询同一个数据在两次查询之间第二个事务访问并改写了该数据导致第一个事务两次查询同一个数据得到的结果不一样。
3幻读Phantom read
幻读和不可重复读类似。它发生在第一个事务在其生命周期进行了两次按同一查询条件查询数据第一次按该查询条件读取了几行数据这时第二个事务进来了且插入或删除了一些数据然后第一个事务再次按同一条件查询发现多了一些原本不存在的记录或者原有记录不见了。
为了解决并发问题TransactionDefinition接口定义了5个事务隔离常量如下
这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。 ISOLATION_DEFAULT 采用数据库默认的事务隔离级别 。MySql 的默认为 REPEATABLE_READ可重复读 Oracle 默认为 READ_COMMITTED读已提交。 【REPEATABLE_READ存在幻读的情况但MySQL的InnoDB解决了幻读】ISOLATION_READ_UNCOMMITTED读未提交。允许另外一个事务读取到当前事务未提交的数据隔离级别最低未解决任何并发问题会产生脏读不可重复读和幻读。ISOLATION_READ_COMMITTED读已提交。被一个事务修改的数据提交后才能被另外一个事务读取另外一个事务不能读取该事务未提交的数据。解决脏读但还存在不可重复读与幻读。ISOLATION_REPEATABLE_READ可重复读。解决脏读、不可重复读存在幻读 ISOLATION_SERIALIZABLE串行化读。按时间顺序一一执行多个事务每次读都需要获得表级共享锁读写相互都会阻塞不存在并发问题最可靠但性能与效率最低。 从第2到第5隔离级别越来越高。
II、事务传播行为常量
定义了七个事务传播行为常量(掌握) 所谓事务传播行为是指处于不同事务中的方法在相互调用时执行期间事务的维护情况合并互斥。 如A 事务中的方法 doSome()调用 B 事务中的方法 doOther()在调用执行期间事务的维护情况就称为事务传播行为。事务传播行为是加在方法上的。 事务传播行为常量都是以 PROPAGATION_ 开头形如 PROPAGATION_XXX。 PROPAGATION_REQUIRED 必须包含事务增删改必用 PROPAGATION_REQUIRES_NEW 自己新开一个事务不管之前是否有事务 PROPAGATION_SUPPORTS 支持事务如果加入的方法有事务则支持事务如果没有不单开事务 PROPAGATION_NEVER 不能运行在事务中如果包在事务中抛异常 PROPAGATION_NOT_SUPPORTED 不支持事务运行在非事务环境中如果加入的方法有事务则会把事务先挂起【不常用】 PROPAGATION_MANDATORY 必须包在事务中没有事务则抛异常 PROPAGATION_NESTED嵌套事务 最后的两个不怎么常用了解一下即可。 a、 PROPAGATION_REQUIRED
指定的方法必须在事务内执行。若当前存在事务就加入到当前事务中 若当前没有事务则创建一个新事务。这种传播行为是最常见的选择也是 Spring 默认的事务传播行为。 如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther() 方法时就是在事务内运行的则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用 doOther()方法时没有在事务内执行则 doOther()方法会创建一个事务并在其中执行。 b、PROPAGATION_SUPPORTS
指定的方法支持当前事务但若当前没有事务也可以以非事务方式执行。 c、 PROPAGATION_REQUIRES_NEW
总是新建一个事务若当前存在事务就将当前事务挂起直到新事务执行完毕。 III、事务默认超时时限常量【了解即可】
定义了默认事务超时时限 常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限及不支持事务超时时限设置的none值。 注意事务的超时时限起作用的条件比较多且超时的时间计算点较复杂。所以该值一般就使用默认值即可。 2.3 程序举例环境搭建
举例购买商品 trans_sale 项目
本例要实现购买商品模拟用户下订单向订单表添加销售记录从商品表减少库存。
实现步骤
Step0创建数据库表
创建两个数据库表 sale , goods
sale 销售表 goods 商品表 goods 表数据 创建项目 Step1: maven 依赖 pom.xml
dependenciesdependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopetest/scope/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.3.26/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.11/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion2.1.0/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.29/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.2.8/version/dependency
/dependencies !--插件--
buildresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resource/resourcespluginsplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-compiler-plugin/artifactIdversion3.11.0/versionconfigurationsource1.8/sourcetarget1.8/target/configuration/plugin/plugins
/build
Step2创建实体类
创建实体类 Sale 与 Goods goods实体类
package com.ambow.pojo;
//dao是数据访问层
//service是业务层
public class Goods {private Integer id;private String nname;private Integer amount;private float price;
}sale实体类
package com.ambow.pojo;public class Sale {private Integer id;private Integer gid;private Integer nums;
}Step3定义 dao 接口
定义两个 dao 的接口 SaleDao , GoodsDao goodsdao数据访问层
package com.ambow.dao;import com.ambow.pojo.Goods;public interface GoodsDao {int updateGoods(Goods goods);Goods selectGoodsById(int id);
}saledao数据访问层
package com.ambow.dao;import com.ambow.pojo.Sale;public interface SaleDao {int insertSale(Sale sale);
}Step4定义 dao 接口对应的 sql 映射文件
SaleDao.xml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.ambow.dao.SaleDaoinsert idinsertSaleinsert into sale (gid,nums) values (#{gid},#{nums})/insert
/mapper
GoodsDao.xml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.ambow.dao.GoodsDaoupdate idupdateGoodsupdate goodsset amount amount - #{amount}where id #{id};/updateselect idselectGoodsById resultTypecom.ambow.pojo.Goodsselect * from goods where id #{id}/select
/mapper update返回的是影响的行数 业务描述 Step5定义异常类
定义 service 层可能会抛出的异常类 NotEnoughException package com.ambow.exception;
//库存不足的时候的异常抛出
public class NotEnoughException extends RuntimeException{public NotEnoughException(){super();}public NotEnoughException(String msg){super(msg);}
}Step6定义 Service 接口
定义 Service 接口 BuyGoodsService package com.ambow.service;public interface BuyGoodsService {public void buy(Integer goodsId,Integer amount);
}Step7定义 service 的实现类
定义 service 层接口的实现类 BuyGoodsServiceImpl
1类定义 2Dao 属性 3Buy 方法 完整代码段
package com.ambow.service.impl;import com.ambow.dao.GoodsDao;
import com.ambow.dao.SaleDao;
import com.ambow.exception.NotEnoughException;
import com.ambow.pojo.Goods;
import com.ambow.pojo.Sale;
import com.ambow.service.BuyGoodsService;
import org.springframework.transaction.annotation.Transactional;public class BuyGoodsServiceImpl implements BuyGoodsService {//1.SaleDao - 添加销售记录private SaleDao saleDao;//2.GoodsDao - 修改库存private GoodsDao goodsDao;//添加两个set方法public void setSaleDao(SaleDao saleDao) {this.saleDao saleDao;}public void setGoodsDao(GoodsDao goodsDao) {this.goodsDao goodsDao;}//购买商品TransactionalOverridepublic void buy(Integer goodsId, Integer amount) {//1.添加销售记录Sale sale new Sale();sale.setGid(goodsId);sale.setNums(amount);saleDao.insertSale(sale);//验证商品库存是否存在和商品的库存是否不足Goods goods goodsDao.selectGoodsById(goodsId);if (goods null){throw new NullPointerException(无此商品);}if (goods.getAmount() amount){throw new NotEnoughException(库存不足);}//2.修改库存goods new Goods();goods.setId(goodsId);goods.setAmount(amount);goodsDao.updateGoods(goods);}
}Step8修改 Spring 配置文件内容
声明Mybatis 对象 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/context xmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd!--整合把MyBatis中的核心对象放到Spring容器--!--引入属性配置文件--context:property-placeholder locationclasspath:jdbc.properties /context:component-scan base-packagecom.ambow.service /!--1.DataSource--bean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName value${jdbc.driver} /property nameurl value${jdbc.url} /property nameusername value${jdbc.username} /property namepassword value${jdbc.password} //bean!--2.注册SqlSessionFactoryBean--bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource /property nametypeAliasesPackage valuecom.ambow.pojo /property namemapperLocations valueclasspath*:com/ambow/dao/*.xml //bean!--3.mapper的扫描配置器 - 生成mapper的代理对象--bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namesqlSessionFactoryBeanName valuesqlSessionFactory /property namebasePackage valuecom.ambow.dao //bean!--4.向service层注入Dao--bean idbuyGoodsService classcom.ambow.service.impl.BuyGoodsServiceImplproperty namesaleDao refsaleDao /property namegoodsDao refgoodsDao //bean!--注入的过程--!--dataSource - SqlSessionFactoryBean - MapperScannerConfigurer(生成Dao代理对象) - studentService--!--声明事务管理器--bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource //bean!--声明事务的注解驱动--tx:annotation-driven transaction-managertransactionManager //beans
声明业务层对象 Step9定义测试类
定义测试类 MyTest。现在就可以在无事务代理的情况下运行了。 原先的库存数量 执行测试代码
package com.ambow.test;import com.ambow.service.BuyGoodsService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class TransTest {Testpublic void test01(){ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);BuyGoodsService buyGoodsService (BuyGoodsService) context.getBean(buyGoodsService);buyGoodsService.buy(1001,15);//正常购买
// buyGoodsService.buy(1008,10);//无此商品//buyGoodsService.buy(1001,100);//库存不足}
}数据库里面的数量 对应的sale表里面 另外一种情况
当没有此商品编号时会出现异常 最后一种情况
当此商品库存不足的时候也会出现异常 2.4 使用 Spring 的事务注解管理事务(掌握)
通过Transactional 注解方式可将事务织入到相应 public 方法中实现事务管理。
Transactional 的所有可选属性如下所示 propagation用于设置事务传播属性。该属性类型为 Propagation 枚举 默认值为 Propagation.REQUIRED。 isolation用于设置事务的隔离级别。该属性类型为 Isolation 枚举默认 值为 Isolation.DEFAULT。 readOnly用于设置该方法对数据库的操作是否是只读的。该属性为 boolean默认值为 false【可修改】。 timeout用于设置本操作与数据库连接的超时时限。单位为秒类型为 int 默认值为-1即没有时限。 rollbackFor指定需要回滚的异常类。类型为 Class[]默认值为空数组。 当然若只有一个异常类时可以不使用数组。 rollbackForClassName指定需要回滚的异常类类名。类型为 String[]默 认值为空数组。当然若只有一个异常类时可以不使用数组。 noRollbackFor指定不需要回滚的异常类。类型为 Class[]默认值为空数 组。当然若只有一个异常类时可以不使用数组。 noRollbackForClassName指定不需要回滚的异常类类名。类型为 String[] 默认值为空数组。当然若只有一个异常类时可以不使用数组。 需要注意的是Transactional 若用在方法上只能用于 public 方法 上。对于其他非 public 方法如果加上了注解Transactional虽然 Spring 不会报错但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的Transaction 注解。若Transaction 注解在类上则表示该类上所有的方法均将在执行时织入事务。 实现注解的事务步骤
复制 trans_sale 项目新项目 trans_sale_annotation
1. 声明事务管理器 要实现事务管理需要先添加事务管理器声明。
基于mybatis的项目需要使用datasourcetransactionmanager此处的属性四指定数据源
2. 开启注解驱动 transaction-manager 上述的内容在前面2.3.8里面已经写了 此处注意选择第四个tx开头的这个 事务管理器 bean 的 id与1.相同
3. 业务层 public 方法加入事务属性
第一句是需要有事务
此处事务回滚是发生库存不足和商品为空时的class
此处可以直接写下面注释的那部分即可
//默认的已有rollbackfor事务回滚此处可以直接省略Transactional(Propagation Propagation.REQUIRED,rollbackFor {NotEnoughException.class,NullPointerException.class})// Transactional
2.5 使用 AspectJ 的 AOP 配置管理事务(掌握)
使用 XML 配置事务代理的方式的不足是每个目标类都需要配置事务代 理。当目标类较多配置文件会变得非常臃肿。
使用 XML 配置顾问方式可以自动为每个符合切入点表达式的类生成事务代 理。其用法很简单只需将前面代码中关于事务代理的配置删除再替换为如 下内容即可。
Step1复制项目
复制 trans_sale 项目并重命名为 trans_sal_aspectj。在此基础上修改。此处直接新建一个项目
Step2maven 依赖 pom.xml
新加入 aspectj 的依赖坐标
dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion5.3.26/version
/dependency Step3在容器中添加事务管理器
!--声明事务管理器--bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource //bean
Step4配置事务通知
为事务通知设置相关属性。用于指定要将事务以什么方式织入给哪些方法。 例如应用到 buy 方法上的事务要求是必须的且当 buy 方法发生异常后要回滚业务。 可以将全部的都在此处配置配置完成之后修改起来只要修改此处即可
!--声明事务的注解驱动--!--tx:annotation-driven transaction-managertransactionManager /--!--添加通知 通知的ID是购买的参数--tx:advice idbuyAdvice transaction-managertransactionManager!-- 增强 先添加事务propagation 其isolation选择默认即可 回滚直接写类名还有我们自己创建的一个事务回滚 两个事务之间使用逗号隔开--tx:attributestx:method namebuy propagationREQUIRED isolationDEFAULTrollback-forjava.lang.NullPointerException,com.ambow.exception.NotEnoughException/!--在开发时有许多的add方法直接写全部的在发生异常时全部回滚--tx:method nameadd* propagationREQUIRED isolationDEFAULTrollback-forjava.lang.Exception/!--给所有的方法度加入method--tx:method name* propagationSUPPORTS //tx:attributes/tx:advice
Step5配置增强器
指定将配置好的事务通知织入给谁。【次粗通过aop织入】 此处指定切入点表达式指定传进来的包【此处为任意包里面的任意service里面的任意方法以及对应的方法名】再加入增强的通知 aop:configaop:pointcut idservicePt expressionexecution(* *..service..*.*(..))/aop:advisor advice-refbuyAdvice pointcut-refservicePt //aop:config
Step6修改测试类
测试类中要从容器中获取的是目标对象。 此处将原来的注解方式先注释接着运行测试类可以看到aop的方式也可以 接着运行测试即可 总结
以上就是今天的内容~
欢迎大家点赞收藏⭐转发 如有问题、建议请您在评论区留言哦。
最后转载请注明出处