目录 [TOC]
MyBatis https://mybatis.net.cn/
实体类和建表语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Data public class UserEntity implements Serializable { private Object id; private String username; private String password; private String gender; private static final long serialVersionUID = 1L ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Data public class Dept implements Serializable { private Object deptId; private Integer deptName; private List<Emp> emps; private static final long serialVersionUID = 1L ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Data public class Emp implements Serializable { private Object empId; private String empName; private Integer age; private String gender; private Integer deptId; private Dept dept; private static final long serialVersionUID = 1L ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CREATE TABLE `user ` ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id' , `username` varchar (255 ) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户名' , `password` varchar (255 ) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码' , `gender` varchar (1 ) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别【0:男 1:女】' , PRIMARY KEY (`id`) ) ENGINE= InnoDB AUTO_INCREMENT= 123 DEFAULT CHARSET= utf8mb4 COLLATE = utf8mb4_general_ci COMMENT= '用户表' ; CREATE TABLE `dept` ( `dept_id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '部门id' , `dept_name` int NOT NULL COMMENT '部门名称' , PRIMARY KEY (`dept_id`) ) ENGINE= InnoDB AUTO_INCREMENT= 1001 DEFAULT CHARSET= utf8mb4 COLLATE = utf8mb4_general_ci COMMENT= '部门表' CREATE TABLE `emp` ( `emp_id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '员工id' , `emp_name` varchar (255 ) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '员工名称' , `age` int DEFAULT NULL COMMENT '年龄' , `gender` varchar (255 ) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别' , `dept_id` int DEFAULT NULL COMMENT '部门id' , PRIMARY KEY (`emp_id`) ) ENGINE= InnoDB AUTO_INCREMENT= 21 DEFAULT CHARSET= utf8mb4 COLLATE = utf8mb4_general_ci COMMENT= '员工表'
mybatis-hello 创建数据库 1 2 3 4 5 6 7 CREATE TABLE `user ` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id' , `username` VARCHAR ( 255 ) NULL COMMENT '用户名' , `password` VARCHAR ( 255 ) NULL COMMENT '密码' , `gender` VARCHAR ( 1 ) NULL COMMENT '性别【0:男 1:女】' , PRIMARY KEY ( `id` ) ) COMMENT= '用户信息' ;
创建maven项目且导入依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.7</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.30</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > </dependency > </dependencies >
创建mybatis核心配置文件 习惯上命名为mybatis-config.xml
。 核心配置文件主要用于配置连接数据库的环境以MyBatis的全局配置信息核心配置文件存放的位置是src/main/resources
目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/ssm-study?serverTimezone=UTC" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="mappers/UserMapper.xml" /> </mappers > </configuration >
新建mapper接口和mapper配置文件 放在src/main/java下面
1 2 3 4 5 6 7 public interface UserMapper { int insert () ; }
命名规则为实体类接口名称+Mapper.xml,例如上面为UserMapper,则XML文件为UserMapper.xml
注意:还需要在mybatis的核心配置文件mybatis-config.xml中的mappers标签中将该XML指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?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.xiaofei.mybatis.mapper.UserMapper" > <insert id ="insert" > insert into user(username, password, gender) value(1,1,1) </insert > </mapper >
编写sqlSession工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 java.io.IOException;import java.io.InputStream;public class SqlSessionUtil { public static SqlSession getSqlSession () { SqlSession sqlSession = null ; try { InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); sqlSession = sqlSessionFactory.openSession(true ); } catch (IOException e) { e.printStackTrace(); } return sqlSession; } }
编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import com.xiaofei.mybatis.mapper.UserMapper;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.InputStream;public class UserTest { @Test public void test () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); int result = userMapper.insert(); System.out.println("结果:" +result); sqlSession.close(); } }
添加日志框架Log4j
log4j配置文件名为log4j.xml存放位置是src/main/resources
目录下面
日志级别:fatal(致命)> error(错误)> warn(警告)> info(信息)> debug(调试)
从左到右打印的内容越来越详细【debug日志信息最全】
mybatis配置文件详解
配置文件中的标签必须按照固定的顺序
官方文档地址:https://mybatis.net.cn/configuration.html
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <properties resource ="jdbc.properties" /> <typeAliases > <package name ="com.xiaofei.mybatis.entity" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > <environment id ="prod" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <package name ="com.xiaofei.mybatis.mapper" /> </mappers > </configuration >
mybatis查询返回
查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射 关系
resultType:自动映射,用于属性名和表中字段名一致的情况
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
1 2 3 4 5 6 7 8 <select id ="resultType" resultType ="" > SELECT *FROM user </select > <select id ="resultMap" resultMap ="" > SELECT *FROM user </select >
mybatis参数获取
#{}(推荐使用):占位符赋值,若为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
${}(不推荐使用):字符串拼接,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引
如果有多个参数,则需要使用@Param参数来标识参数
1 int insert (@Param("username") String username, @Param("password") String password) ;
1 2 3 <insert id ="insert" > INSERT INTO `user`(username, password) value (#{username}, #{password}) </insert >
mybatis各种查询 获取sqlSession工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 java.io.IOException;import java.io.InputStream;public class SqlSessionUtil { public static SqlSession getSqlSession () { SqlSession sqlSession = null ; try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); sqlSession = sqlSessionFactory.openSession(true ); } catch (IOException e) { e.printStackTrace(); } return sqlSession; } }
查询一个实体类对象 1 UserEntity selectById (@Param("id") Long id) ;
1 2 3 4 <select id ="selectById" resultType ="com.xiaofei.mybatis.entity.UserEntity" > SELECT *FROM user WHERE id = #{id} </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void selectById () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); System.out.println(userMapper.selectById(1L )); sqlSession.close(); }
查询一个list集合 1 List<UserEntity> selectList () ;
1 2 3 4 <select id ="selectList" resultType ="com.xiaofei.mybatis.entity.UserEntity" > SELECT *FROM user </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void selectList () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); userMapper.selectList().forEach(System.out::println); sqlSession.close(); }
查询单个数据
mybatis中给Java类名已经设置了别名,具体使用查看链接:https://mybatis.net.cn/configuration.html#typeAliases
1 2 3 4 <select id ="count" resultType ="java.lang.Integer" > SELECT COUNT(*) FROM user </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void count () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); System.out.println(userMapper.count()); sqlSession.close(); }
查询返回Map 查询一条数据为map对象 1 Map<String, Object> selectMap (@Param("id") Long id) ;
1 2 3 4 <select id ="selectMap" resultType ="java.util.Map" > SELECT *FROM user WHERE id = #{id} </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void selectMap () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); System.out.println(userMapper.selectMap(1L )); sqlSession.close(); }
查询多条数据为map集合 1 List<Map<String, Object>> selectMapList () ;
1 2 3 <select id ="selectMapList" resultType ="java.util.Map" > SELECT *FROM user </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void selectMapList () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); userMapper.selectMapList().forEach(System.out::println); sqlSession.close(); }
使用MapKey注解(不推荐使用) @MapKey:将查询的某个字段的值作为大的map的键
查询一条数据
1 2 @MapKey("id") Map<String, Object> selectMap (@Param("id") Long id) ;
查询多条数据
1 2 @MapKey("id") Map<String, Object> selectMapList () ;
特殊SQL执行 模糊查询 1 List<UserEntity> getByUsername (@Param("username") String username) ;
1 2 3 4 5 6 7 8 9 10 11 <select id ="getByUsername" resultType ="com.xiaofei.mybatis.entity.UserEntity" > SELECT *FROM `user` WHERE `username` LIKE "%"#{username}"%" </select >
批量删除
推荐使用可以查看动态SQL来实现批量删除
1 int batchDelete (@Param("ids") String ids) ;
1 2 3 4 <delete id ="batchDelete" > DELETE FROM `user` WHERE id IN (${ids}) </delete >
动态设置表名 1 List<UserEntity> getByUsername (@Param("tableName") String tableName) ;
1 2 3 4 <select id ="getByUsername" resultType ="com.xiaofei.mybatis.entity.UserEntity" > SELECT *FROM ${tableName} </select >
添加功能获取自增的主键 在JDBC中就已经可以实现新增获取自增主键,mybatis是封装的JDBC
1 void insertUser (UserEntity user) ;
1 2 3 4 5 6 7 8 9 <insert id ="insertUser" useGeneratedKeys ="true" keyProperty ="id" parameterType ="com.xiaofei.mybatis.entity.UserEntity" > INSERT INTO `user` (username, password, gender) VALUES (#{username}, #{password}, #{gender}) </insert >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void insertUser () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); UserEntityMapper userMapper = sqlSession.getMapper(UserEntityMapper.class); UserEntity userEntity = new UserEntity (); userEntity.setUsername("1" ); userEntity.setGender("2" ); userEntity.setPassword("3" ); userMapper.insertUser(userEntity); System.out.println(userEntity.getId()); sqlSession.close(); }
自定义映射resultMap
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射
数据库字段和类属性处理 起别名 1 Emp getById (@Param("id") Integer id) ;
1 2 3 4 5 <select id ="getById" resultType ="com.xiaofei.mybatis.entity.Emp" > SELECT emp_id empId, emp_name empName, age, gender FROM emp WHERE emp_id = #{id} </select >
全局配置字段匹配规则为驼峰
修改mybatis核心配置文件mybatis-config.xml中的setting
setting标签具体配置:https://mybatis.net.cn/configuration.html#settings
1 2 3 4 <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings >
1 2 3 4 <select id ="getById" resultType ="com.xiaofei.mybatis.entity.Emp" > SELECT *FROM emp WHERE emp_id = #{id} </select >
1 Emp getById (@Param("id") Integer id) ;
使用resultMap自定义映射 1 Emp getById (@Param("id") Integer id) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <resultMap id ="BaseResultMap" type ="com.xiaofei.mybatis.entity.Emp" > <id property ="empId" column ="emp_id" jdbcType ="OTHER" /> <result property ="empName" column ="emp_name" jdbcType ="VARCHAR" /> <result property ="age" column ="age" jdbcType ="INTEGER" /> <result property ="gender" column ="gender" jdbcType ="VARCHAR" /> </resultMap > <select id ="getById" resultMap ="BaseResultMap" > SELECT *FROM emp WHERE emp_id = #{id} </select >
多对一/一对一映射处理 使用级联方式处理映射关系 1 Emp selectById (@Param("empId") Integer empId) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <resultMap id ="BaseResultMap" type ="com.xiaofei.mybatis.entity.Emp" > <id property ="empId" column ="emp_id" jdbcType ="OTHER" /> <result property ="empName" column ="emp_name" jdbcType ="VARCHAR" /> <result property ="age" column ="age" jdbcType ="INTEGER" /> <result property ="gender" column ="gender" jdbcType ="VARCHAR" /> <result property ="deptId" column ="dept_id" jdbcType ="INTEGER" /> <result property ="dept.deptId" column ="dept_id" /> <result property ="dept.deptName" column ="dept_name" /> </resultMap > <select id ="selectById" resultMap ="BaseResultMap" > SELECT * FROM emp LEFT JOIN dept ON emp.dept_id = dept.dept_id WHERE emp.emp_id = #{empId} </select >
使用association处理映射关系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <resultMap id ="AssociationResultMap" type ="com.xiaofei.mybatis.entity.Emp" > <id property ="empId" column ="emp_id" jdbcType ="INTEGER" /> <result property ="empName" column ="emp_name" jdbcType ="VARCHAR" /> <result property ="age" column ="age" jdbcType ="INTEGER" /> <result property ="gender" column ="gender" jdbcType ="VARCHAR" /> <result property ="deptId" column ="dept_id" jdbcType ="INTEGER" /> <association property ="dept" column ="dept" > <id property ="deptId" column ="dept_id" jdbcType ="INTEGER" /> <result property ="deptName" column ="dept_name" jdbcType ="VARCHAR" /> </association > </resultMap > <select id ="selectById" resultMap ="BaseResultMap" > SELECT * FROM emp LEFT JOIN dept ON emp.dept_id = dept.dept_id WHERE emp.emp_id = #{empId} </select >
使用association进行分步查询 ①dept
1 Dept selectById (@Param("deptId") String deptId) ;
1 2 3 <select id ="selectById" resultType ="com.xiaofei.mybatis.entity.Dept" > SELECT *FROM dept WHERE dept_id = #{deptId} </select >
②emp
1 Emp selectByStep (@Param("empId") Integer empId) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <resultMap id ="AssociationByStep" type ="com.xiaofei.mybatis.entity.Emp" > <id property ="empId" column ="emp_id" jdbcType ="INTEGER" /> <result property ="empName" column ="emp_name" jdbcType ="VARCHAR" /> <result property ="age" column ="age" jdbcType ="INTEGER" /> <result property ="gender" column ="gender" jdbcType ="VARCHAR" /> <result property ="deptId" column ="dept_id" jdbcType ="INTEGER" /> <association property ="dept" select ="com.xiaofei.mybatis.mapper.DeptMapper.selectById" column ="dept_id" /> </resultMap > <select id ="selectByStep" resultMap ="AssociationByStep" > SELECT *FROM emp WHERE emp_id = #{empId} </select >
一对多映射处理 使用collection处理映射关系 1 Dept selectInfoById (@Param("deptId") Integer deptId) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <resultMap id ="CollectionResultMap" type ="com.xiaofei.mybatis.entity.Dept" > <id property ="deptId" column ="dept_id" jdbcType ="OTHER" /> <result property ="deptName" column ="dept_name" jdbcType ="VARCHAR" /> <collection property ="emps" ofType ="com.xiaofei.mybatis.entity.Emp" > <id property ="empId" column ="emp_id" jdbcType ="INTEGER" /> <result property ="empName" column ="emp_name" jdbcType ="VARCHAR" /> <result property ="age" column ="age" jdbcType ="INTEGER" /> <result property ="gender" column ="gender" jdbcType ="VARCHAR" /> <result property ="deptId" column ="dept_id" jdbcType ="INTEGER" /> </collection > </resultMap > <select id ="selectInfoById" resultMap ="CollectionResultMap" > SELECT * FROM dept LEFT JOIN emp ON dept.dept_id = emp.dept_id WHERE dept.dept_id = #{deptId} </select >
使用collection进行分步查询 ①emp
1 List<Emp> selectByDeptId (@Param("deptId") Integer deptId) ;
1 2 3 4 5 <select id ="selectByDeptId" resultType ="com.xiaofei.mybatis.entity.Emp" > SELECT * FROM emp WHERE dept_id = #{deptId} </select >
②dept
懒加载具体使用查看分步查询优点
1 Dept selectInfoById (@Param("deptId") Integer deptId) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="CollectionResultMapStep" type ="com.xiaofei.mybatis.entity.Dept" > <id property ="deptId" column ="dept_id" jdbcType ="OTHER" /> <result property ="deptName" column ="dept_name" jdbcType ="VARCHAR" /> <collection property ="emps" fetchType ="eager" select ="com.xiaofei.mybatis.mapper.EmpMapper.selectByDeptId" column ="dept_id" /> </resultMap > <select id ="selectInfoById" resultMap ="CollectionResultMapStep" > SELECT * FROM dept WHERE dept.dept_id = #{deptId} </select >
分步查询优点
分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,
fetchType=”lazy(延迟加载)|eager(立即加载)”
动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
if
if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行,搭配where
标签一起使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="selectList" resultType ="com.xiaofei.mybatis.entity.Emp" > SELECT *FROM emp <where > <if test ="empId != null and empId != ''" > AND `emp_id` = #{empId} </if > <if test ="empName != null and empName != ''" > AND `emp_name` = #{empName} </if > <if test ="age != null and age != ''" > AND `age` = #{age} </if > <if test ="gender != null and gender != ''" > AND `gender` = #{gender} </if > <if test ="deptId != null and deptId != ''" > AND `dept_id` = #{deptId} </if > </where > </select >
where
where和if一般结合使用:
若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
注意:where标签不能去掉条件最后多余的and
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="selectList" resultType ="com.xiaofei.mybatis.entity.Emp" > SELECT *FROM emp <where > <if test ="empId != null and empId != ''" > AND `emp_id` = #{empId} </if > <if test ="empName != null and empName != ''" > AND `emp_name` = #{empName} </if > <if test ="age != null and age != ''" > AND `age` = #{age} </if > <if test ="gender != null and gender != ''" > AND `gender` = #{gender} </if > <if test ="deptId != null and deptId != ''" > AND `dept_id` = #{deptId} </if > </where > </select >
trim
trim用于去掉或添加标签中的内容
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <insert id ="insert" > INSERT INTO emp <trim prefix ="(" suffix =")" suffixOverrides ="," > <if test ="empId != null and empId != ''" > `emp_id`, </if > <if test ="empName != null and empName != ''" > `emp_name`, </if > <if test ="age != null and age != ''" > `age`, </if > <if test ="gender != null and gender != ''" > `gender`, </if > <if test ="deptId != null and deptId != ''" > `dept_id`, </if > </trim > <trim prefix ="values (" suffix =")" suffixOverrides ="," > <if test ="empId != null and empId != ''" > #{empId}, </if > <if test ="empName != null and empName != ''" > #{empName}, </if > <if test ="age != null and age != ''" > #{age}, </if > <if test ="gender != null and gender != ''" > #{gender}, </if > <if test ="deptId != null and deptId != ''" > #{deptId}, </if > </trim > </insert >
choose、when、otherwise
choose、when、otherwise相当于if…else。当有一个when标签满足后,后面的when标签将不会再进行比较
1 Dept chooseUse (Dept dept) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="chooseUse" resultType ="com.xiaofei.mybatis.entity.Dept" > SELECT * FROM dept <where > <choose > <when test ="deptId != null and deptId != ''" > AND `dept_id` = #{deptId} </when > <when test ="deptName != null and deptName != ''" > AND `dept_name` = #{deptName} </when > </choose > </where > </select >
foreach
collection:设置要循环的数组或集合
item:用一个字符串表示数组或集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么开始
close:循环的所有内容以什么结束
1 2 3 4 5 6 7 8 9 int insertBatch (@Param("depts") List<Dept> depts) ;int deleteBatch (@Param("ids") List<Integer> ids) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <insert id ="insertBatch" > INSERT INTO dept ( dept_name ) VALUES <foreach collection ="depts" item ="dept" separator ="," > (#{dept.deptName}) </foreach > </insert > <delete id ="deleteBatch" > DELETE FROM dept WHERE dept_id IN <foreach collection ="ids" item ="id" separator ="," open ="(" close =")" > #{id} </foreach > </delete >
动态SQL
可以记录一段sql,在需要用的地方使用include标签进行引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <sql id ="Base_Column_List" > `emp_id`, `emp_name`, `age`, `gender`, `dept_id` </sql > <sql id ="Base_Select_If" > <where > <if test ="empId != null and empId != ''" > AND `emp_id` = #{empId} </if > <if test ="empName != null and empName != ''" > AND `emp_name` = #{empName} </if > <if test ="age != null and age != ''" > AND `age` = #{age} </if > <if test ="gender != null and gender != ''" > AND `gender` = #{gender} </if > <if test ="deptId != null and deptId != ''" > AND `dept_id` = #{deptId} </if > </where > </sql > <select id ="selectList" resultType ="Emp" > SELECT <include refid ="Base_Column_List" /> FROM emp <include refid ="Base_Select_If" /> </select >
mybatis缓存 mybatis一级缓存 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查
询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:
不同的SqlSession对应不同的一级缓存
同一个SqlSession但是查询条件不同
同一个SqlSession两次查询期间执行了任何一次增删改操作
同一个SqlSession两次查询期间手动清空了缓存
mybatis一级缓存默认开启的,不需要手动设置
mybatis二级缓存 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
在核心配置文件mybatis-config.xml
的setting
标签里面设置全局配置属性cacheEnabled=”true”,默认为true,不需要设置
在XxxMapper.xml
映射文件中设置<cache/>
标签
二级缓存必须在SqlSession关闭或提交之后有效
查询的数据所转换的实体类类型必须实现序列化的接口Serializable
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
二级缓存的相关配置 在mapper配置文件中添加的cache标签可以设置一些属性:
size属性:引用数目,正整数代表缓存最多可以存储多少个对象,太大容易导致内存溢出
mybatis缓存查询顺序 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
整个第三方缓存EHcache(很少使用) 添加依赖 1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.mybatis.caches</groupId > <artifactId > mybatis-ehcache</artifactId > <version > 1.2.1</version > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-classic</artifactId > <version > 1.2.3</version > </dependency >
各jar包功能
jar包名称
作用
mybatis-ehcache
MyBatis和EHCache的整合包
ehcache
EHCache核心包
slf4j-api
SLF4J日志门面包
logback-classic
支持SLF4J门面接口的一个具体实现
创建EHCache的配置文件ehcache.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="utf-8" ?> <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="../config/ehcache.xsd" > <diskStore path ="C:\Users\19030\Desktop\tmp\ehcache" /> <defaultCache maxElementsInMemory ="1000" maxElementsOnDisk ="10000000" eternal ="false" overflowToDisk ="true" timeToIdleSeconds ="120" timeToLiveSeconds ="120" diskExpiryThreadIntervalSeconds ="120" memoryStoreEvictionPolicy ="LRU" > </defaultCache > </ehcache >
设置二级缓存类型 1 <cache type ="org.mybatis.caches.ehcache.EhcacheCache" />
加入logback日志
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8" ?> <configuration debug ="true" > <appender name ="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder > <pattern > [%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern > </encoder > </appender > <root level ="DEBUG" > <appender-ref ref ="STDOUT" /> </root > <logger name ="com.xiaofei.mybatis.mapper" level ="DEBUG" /> </configuration >
EHCache配置文件说明
mybatis逆向工程
克隆下面项目地址,进行代码生成
Gitee:https://gitee.com/xiao-i-fei/xiaofei-generator
GitHub:https://github.com/xiao-i-fei/xiaofei-generator
mybatis-pagehelper分页插件使用 官方文档:https://pagehelper.github.io/
引入依赖 1 2 3 4 5 <dependency > <groupId > com.github.pagehelper</groupId > <artifactId > pagehelper</artifactId > <version > 5.3.2</version > </dependency >
使用
在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据
list:分页之后的数据
navigatePages(可选参数):导航分页的页码数,一般为pageNum
值
1 2 3 <select id ="list" resultType ="Dept" > SELECT *FROM dept </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Test public void chooseUse () { SqlSession sqlSession = SqlSessionUtil.getSqlSession(); DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class); PageHelper.startPage(1 ,2 ); List<Dept> depts = deptMapper.list(); PageInfo<Dept> pageInfo = new PageInfo <Dept>(depts, 1 ); depts.forEach(System.out::println); System.out.println(pageInfo); sqlSession.close(); }
参数解释
参数
意义
pageNum
当前页的页码
pageSize
每页显示的条数
size
当前页显示的真实条数
total
总记录数
pages
总页数
prePage
上一页的页码
nextPage
下一页的页码
isFirstPage/isLastPage
是否为第一页/最后一页
hasPreviousPage/hasNextPage:
是否存在上一页/下一页
navigatePages
导航分页的页码数
navigatepageNums
导航分页的页码,[1,2,3,4,5]
Spring Spring Framework Spring Framework特性 Spring 基础框架,可以视为 Spring 基础设施,基本上任何其他 Spring 项目都是以 Spring Framework 为基础的。
非侵入式:使用Spring Framework开发应用程序时,Spring对应用程序本身的结构影响非常小。对领域模型可以做到零污染;对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。这就使得基于Spring Framework开发应用程序时结构清晰、简洁优雅。
控制反转:IOC——Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源变成环境将资源准备好,我们享受资源注入。
面向切面编程:AOP——Aspect Oriented Programming,在不修改源代码的基础上增强代码功能。
容器:Spring IOC 是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发效率。
组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在Spring中可以使用XML和Java注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。
声明式:很多以前需要编写代码才能实现的功能,现在只需要声明需求即可由框架代为实现。
一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且Spring旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在Spring Framework的基础上全部使用Spring来实现。
Spring Framework五大功能模块
功能模块
功能介绍
Core Container
核心容器,在Spring环境下使用任何功能都是必须基于IOC容器
AOP&Aspects
面向切面编程
Testing
提供了对junit或TestNG测试框架的整合
Data Access / Integration
提供了对数据访问 / 集成的功能
Spring MVC
提供了面向Web应用程序的集成功能
IOC IOC容器 IOC思想 IOC:Inversion of Control,翻译过来是反转控制
获取资源的传统方式
自己做饭:买菜、洗菜、择菜、改刀、炒菜,全过程参与,费时费力,必须清楚了解资源创建整个过程中的全部细节且熟练掌握。
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效 率。
反转控制方式获取资源
点外卖:下单、等、吃,省时省力,不必关心资源创建过程的所有细节。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源 的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
DI
DI:Dependency Injection,翻译过来是依赖注入。
DI是IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
所以结论是:IOC就是一种反转控制的思想,而DI是对IOC的一种具体实现
IOC容器在Spring中的实现
类型名
简介
ClassPathXmlApplicationContext
通过读取类路径下的 XML 格式的配置文件创建 IOC 容器 对象
FileSystemXmlApplicationContext
通过文件系统路径读取 XML 格式的配置文件创建 IOC 容 器对象
ConfigurableApplicationContext
ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让ApplicationContext 具有启动、关闭和刷新上下文的能力
WebApplicationContext
专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对 象,并将对象引入存入 ServletContext 域中
基于XML管理bean 引入依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.1</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > </dependency > </dependencies >
创建实体类 1 2 3 4 5 6 7 8 9 @Data @NoArgsConstructor @AllArgsConstructor public class InternalBean { private String deptName; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 @Data @NoArgsConstructor @AllArgsConstructor public class SpringBean { private Integer id; private String username; private String password; private String gender; private String specialValue1; private String specialValue2; private String specialValue3; private String[] hobby; private List<String> otherNames; private Map<String, String> mapValue; private InternalBean internalBean; private List<InternalBean> internalBeans; }
创建配置文件 文件名字为:ApplicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:p ="http://www.springframework.org/schema/p" 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" > <bean id ="springBean" class ="com.xiaofei.spring.SpringBean" > <property name ="id" value ="12" /> <property name ="username" value ="xiaofei" /> <property name ="specialValue1" > <null /> </property > <property name ="specialValue2" value ="a < b" /> <property name ="specialValue3" > <value > <![CDATA[《特殊值3》]]>--></value > </property > <property name ="hobby" > <array > <value > 吃饭</value > <value > 睡觉</value > </array > </property > <property name ="otherNames" > <list > <value > xiaofei1</value > <value > xiaofei2</value > </list > </property > <property name ="mapValue" > <map > <entry key ="key1" value ="value1" /> <entry key ="key2" value ="value2" /> <entry key ="key3" value ="value3" /> </map > </property > <property name ="internalBean" > <bean id ="inner" class ="com.xiaofei.spring.InternalBean" > <property name ="deptName" value ="特殊部门" /> </bean > </property > <property name ="internalBeans" > <list > <ref bean ="internalBean1" /> <ref bean ="internalBean2" /> <ref bean ="internalBean3" /> </list > </property > </bean > <bean id ="internalBean1" class ="com.xiaofei.spring.InternalBean" > <property name ="deptName" value ="开发部门" /> </bean > <bean id ="internalBean2" class ="com.xiaofei.spring.InternalBean" p:deptName ="研发部门" /> <bean id ="internalBean3" class ="com.xiaofei.spring.InternalBean" > <constructor-arg name ="deptName" value ="销售部门" /> </bean > </beans >
1 2 3 4 5 6 7 8 @Test public void test1 () { ApplicationContext ioc = new ClassPathXmlApplicationContext ("ApplicationContext.xml" ); SpringBean springBean = (SpringBean) ioc.getBean("springBean" ); System.out.println(springBean); }
引入外部配置文件 properties文件
spring配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?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: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 https://www.springframework.org/schema/context/spring-context.xsd" > <context:property-placeholder location ="classpath:external.properties" /> <bean id ="internalBean" class ="com.xiaofei.spring.InternalBean" > <property name ="deptName" value ="${external.deptName}" /> </bean > </beans >
测试 1 2 3 4 5 6 7 8 @Test public void test2 () { ApplicationContext ioc = new ClassPathXmlApplicationContext ("ExternalContext.xml" ); InternalBean internalBean = (InternalBean) ioc.getBean("internalBean" ); System.out.println(internalBean); }
Bean作用域
在bean标签的scope
属性指定
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表
取值
含义
创建对象时机
singleton(默认)
在IOC容器中,这个bean的对象始终为单实例
IOC容器初始化时
propotype
这个bean在IOC容器中有多个实例
获取bean时
如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用)
取值
含义
request
在一个请求范围内有效
session
在一个会话范围内有效
bean的生命周期
bean对象创建(调用无参构造器)
给bean对象设置属性
bean对象初始化之前操作(由bean的后置处理器负责)
bean对象初始化(需在配置bean时指定初始化方法)
bean对象初始化之后操作(由bean的后置处理器负责)
bean对象就绪可以使用
bean对象销毁(需在配置bean时指定销毁方法)
IOC容器关闭
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Data @AllArgsConstructor public class InternalBean { private String deptName; public InternalBean () { System.out.println("1、创建对象" ); } public void setDeptName (String deptName) { System.out.println("2、依赖注入" ); this .deptName = deptName; } public void initMethod () { System.out.println("3、初始化" ); } public void destroyMethod () { System.out.println("5、销毁" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:p ="http://www.springframework.org/schema/p" 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" > <bean id ="internalLifeCycle" class ="com.xiaofei.spring.InternalBean" scope ="singleton" init-method ="initMethod" destroy-method ="destroyMethod" > <property name ="deptName" value ="测试部门" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 @Test public void test1 () { ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext ("ApplicationContext.xml" ); InternalBean internalBean = (InternalBean) ioc.getBean("internalLifeCycle" ); System.out.println("4、通过IOC容器获取bean并使用" ); ioc.close(); }
FactoryBean FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
整合Mybatis时,Spring就是通过FactoryBean机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface FactoryBean <T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType" ; @Nullable T getObject () throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton () { return true ; } }
创建UserEntity
1 2 3 @Data public class UserEntity {}
创建UserFactoryBean
1 2 3 4 5 6 7 8 9 10 11 public class UserFactory implements FactoryBean <UserEntity> { @Override public UserEntity getObject () throws Exception { return new UserEntity (); } @Override public Class<?> getObjectType() { return UserEntity.class; } }
配置
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" 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" > <bean class ="com.xiaofei.spring.factory.UserFactory" /> </beans >
使用
1 2 3 4 5 6 7 8 @Test public void test3 () { ApplicationContext ioc = new ClassPathXmlApplicationContext ("SpringFactory.xml" ); UserEntity userEntity = ioc.getBean(UserEntity.class); System.out.println(userEntity); }
基于注解管理Bean 注解
@Component:将类标识为普通组件
@Controller:将类标识为控制层组件
@Service:将类标识为业务层组件
@Repository:将类标识为持久层组件
组件扫描
@Autowired注解自动装配 在成员变量上直接标记@Autowired注解即可完成自动装配,不需要提供setXxx()方法。以后我们在项目中的正式用法就是这样。
@Autowired中有属性required,默认值为true,因此在自动装配无法找到相应的bean时,会装配失败 可以将属性required的值设置为true,则表示能装就装,装不上就不装,此时自动装配的属性为默认值 但是实际开发时,基本上所有需要装配组件的地方都是必须装配的,用不上这个属性
AOP 各种通知
前置通知:使用@Before
注解标识,在被代理的目标方法前执行
返回通知:使用@AfterReturning
注解标识,在被代理的目标方法成功结束后执行(寿终正寝)
异常通知:使用@AfterThrowing
注解标识,在被代理的目标方法异常结束后执行(死于非命)
后置通知:使用@After
注解标识,在被代理的目标方法最终结束后执行(盖棺定论)
环绕通知:使用@Around
注解标识,使用try…catch…finally结构围绕整个被代理的目标方法,环绕通知相当于上面四种通知加起来,所以使用了环绕通知就不使用上面四种通知
通知顺序
Spring版本5.3.x以前:
Spring版本5.3.x以后:
切面优先级 如果一个方法存在多个切面,可以在切面类上面添加org.springframework.core.annotation.Order.Order
注解来标注切面的优先级,配置一个数字,数字越小,优先级越高,如果不指定值,则默认值为Integer类型的最大值
注解AOP使用 依赖 1 2 3 4 5 6 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aspects</artifactId > <version > 5.3.1</version > </dependency >
配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:p ="http://www.springframework.org/schema/p" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <context:component-scan base-package ="com.xiaofei.aop" /> <aop:aspectj-autoproxy /> </beans >
使用 1 2 3 4 5 6 7 8 9 10 public interface UserService { int add (int i, int j) ; int sub (int i, int j) ; int mul (int i, int j) ; int div (int i, int j) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Service public class UserServiceImpl implements UserService { @Override public int add (int i, int j) { int result = i + j; System.out.println("方法内部,result:" +result); return result; } @Override public int sub (int i, int j) { int result = i - j; System.out.println("方法内部,result:" +result); return result; } @Override public int mul (int i, int j) { int result = i * j; System.out.println("方法内部,result:" +result); return result; } @Override public int div (int i, int j) { int result = i / j; System.out.println("方法内部,result:" +result); return result; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;import java.util.Arrays;@Aspect @Component public class AspectTest { @Pointcut("execution(* com.xiaofei.aop.service.UserService.*(..))") public void pointCut () {} @Before("pointCut()") public void beforeAdviceMethod (JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); Object[] args = joinPoint.getArgs(); System.out.println("LoggerAspect,方法:" +signature.getName()+",参数:" + Arrays.toString(args)); } @After("pointCut()") public void afterAdviceMethod (JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); System.out.println("LoggerAspect,方法:" +signature.getName()+",执行完毕" ); } @AfterReturning(value = "pointCut()", returning = "result") public void afterReturningAdviceMethod (JoinPoint joinPoint, Object result) { Signature signature = joinPoint.getSignature(); System.out.println("LoggerAspect,方法:" +signature.getName()+",结果:" +result); } @AfterThrowing(value = "pointCut()", throwing = "ex") public void afterThrowingAdviceMethod (JoinPoint joinPoint, Throwable ex) { Signature signature = joinPoint.getSignature(); System.out.println("LoggerAspect,方法:" +signature.getName()+",异常:" +ex); } @Around("pointCut()") public Object aroundAdviceMethod (ProceedingJoinPoint joinPoint) { Object result = null ; try { System.out.println("环绕通知-->前置通知" ); result = joinPoint.proceed(); System.out.println("环绕通知-->返回通知" ); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("环绕通知-->异常通知" ); } finally { System.out.println("环绕通知-->后置通知" ); } return result; } }
配置文件AOP使用 Spring-Test使用
@RunWith(SpringJUnit4ClassRunner.class):指定当前测试类在Spring的测试环境中执行,此时就可以通过注入的方式直接获取IOC容器中bean
@ContextConfiguration(“classpath:ApplicationContext.xml”):指定配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.3.1</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:ApplicationContext.xml") public class SpringTest { @Autowired private JdbcTemplate template; }
事务 依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.1</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-orm</artifactId > <version > 5.3.1</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > 5.3.1</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.16</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.0.31</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aspects</artifactId > <version > 5.3.1</version > </dependency > </dependencies >
数据库配置文件 1 2 3 4 5 jdbc.driver =com.mysql.cj.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/test?serverTimezone=UTC jdbc.username =root jdbc.password =root
配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?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:context ="http://www.springframework.org/schema/context" xmlns:tx ="http://www.springframework.org/schema/tx" xsi:schemaLocation ="http://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" > <context:property-placeholder location ="classpath:jdbc.properties" /> <context:component-scan base-package ="com.xiaofei.transactional" /> <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 class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:annotation-driven transaction-manager ="transactionManager" /> </beans >
测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.transaction.annotation.Transactional;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:ApplicationContext.xml") public class SpringTest { @Autowired private JdbcTemplate jdbcTemplate; @Test @Transactional public void insert () { String sql = "insert into user(username, password, gender) values(?,?,?)" ; jdbcTemplate.update(sql, 1 , 1 , 1 ); int a = 10 / 0 ; } }
SpringMVC