一、Mybatis简介
二、Mybatis的第一个程序
思路👇
- 搭建环境
- 导入Mybatis jar包
- 编写代码
- 测试
1、搭建环境
- 创建表
create database Mybatis; use Mybatis; create table user(id int(20) not null, name varchar(50), pwd varchar(50),primary key(id)) engine=innodb default charset=utf8; insert into user values(1,'郭洋','123456'), (2,'张三','45678'), (3,'李四','989765');
- 新建项目(Maven项目)
- 删除src目录
- 导入依赖
<!--导入依赖--> <dependencies> <!--导入mysql依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--导入mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies> <!--在build中配置resource,来防止我们资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
2、创建Module
- 编写mybatis核心配置文件
<?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"> <!--事务管理使用的是JDBC--> <transactionManager type="JDBC"/> <!--配置数据源--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true;useUnicode=true;characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root123456"/> </dataSource> </environment> </environments> // 每个mapper.xml文件都需要在核心配置文件中配置 <mappers> <mapper resource="com/yang/mapper/userMapper.xml"/> </mappers> </configuration>
- 编写mybatis工具类
public class MybatisUtils { String resource = "mybatis-config.xml"; private static SqlSessionFactory sqlSessionFactory; InputStream inputStream; { try { //获取sqlSessionFactory对象 inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ SqlSession sqlSession = sqlSessionFactory.openSession(); return sqlSession; } }
3、编写代码
- 实体类
@Data @NoArgsConstructor @AllArgsConstructor public class userPo { private int id; private String name; private String pwd; }
- Mapper接口
public interface userMapper { List<userPo> getUserList(); }
- 编写mapper.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.yang.mapper.userMapper"> <select id="getUserList" resultType="com.yang.po.userPo"> select * from user </select> </mapper>
4、测试
- 测试
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); List<userPo> userList = mapper.getUserList(); for (userPo user:userList) { System.out.println(user); } }
- 问题:
- 1、org.apache.ibatis.binding.BindingException: Type interface com.yang.mapper.userMapper is not known to the MapperRegistry.
- 说明:每一个Mapper.xml都需要在Mybatis核心配置文件中注册
<mappers> <mapper resource="com/yang/mapper/userMapper.xml"/> </mappers>
- 解释:默认从resources中读取,如果文件不是写在resources下就要配置
- 2、可能会遇到我们写的xml文件无法导出或不生效的问题。
- 解决方案:在pom文件中配置,使resources下和src/main/java下的文件可以被导出。
<!--在build中配置resource,来防止我们资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resource</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
- JDBC连接出错Sat Oct 24 12:36:27 CST 2020 WARN: Establishing SSL connection without server‘s identity ver
- 解决方案:String url = “jdbc:mysql://localhost:3306/text?useSSL=false”;在jdbcURL属性标签中添加这样的一行代码便会跳过SSL验证数据库名后加上?useSSL=false
- 说明:工具类创建sqlSession的过程
三、增删该查操作
1、namespace
- namespace中的包名要和mapper接口的包名一致
2、selece
1、编写接口
userPo getUserById(int id);
2、编写mapper.xml中sql语句
<select id="getUserById" resultType="com.yang.po.userPo"> select * from user where id=#{id} </select>
3、测试
@Test public void getUserByIdTest(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); userPo user = mapper.getUserById(3); System.out.println(user); sqlSession.close(); }
3、insert
- .xml代码
<insert id="insertUser" parameterType="com.yang.po.userPo"> insert into user values (#{id},#{name},#{pwd}) </insert>
- 测试
@Test public void insertUserTest(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); userPo userPo = new userPo(); userPo.setId(10); userPo.setName("洋洋洋"); userPo.setPwd("666"); Integer integer = mapper.insertUser(userPo); if(integer > 0){ sqlSession.commit(); } sqlSession.close(); }
4、update
- .xml代码
<update id="upDateUser" parameterType="com.yang.po.userPo"> update user set name=#{name},pwd=#{pwd} where id = #{id} </update>
- 测试
@Test public void upDateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); userPo userPo = new userPo(3,"李四","666"); Integer integer = mapper.upDateUser(userPo); if(integer > 0){ sqlSession.commit(); } sqlSession.close(); }
5、delete
- .xml代码
<delete id="deleteUser" > delete from user where id= #{id} </delete>
- 测试
@Test public void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); Integer integer = mapper.deleteUser(10); if (integer > 0) { sqlSession.commit(); } sqlSession.close(); }
6、注意点
- 增删改需要提交事物
7、使用Map的
1、mapper中的方法
Integer insertUserByMap(Map<String,Object> map);
2、.xml代码
<insert id="insertUserByMap" parameterType="Map"> insert into user (id,name) values (#{mapId},#{mapPwd}) </insert>
3、测试
@Test public void insertUserByMap(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); Map<String,Object> map = new HashMap<String, Object>(); map.put("mapId",7); map.put("mapPwd","000"); Integer integer = mapper.insertUserByMap(map); if(integer > 0){ sqlSession.commit(); } sqlSession.close(); } }
- Map传递参数,直接在sql中取出key即可!【parameterType="map"】
- 对象传递参数,直接在sql中去对象的属性即可!【parameterType="Object"】
- 只有一个基本数据类型参数的情况下,可以直接在sql中取到!
- 多个参数用Map
8、思考
模糊查询怎么写?
- 1、java代码执行的时候,传递通配符% %
List<user> userList = mapper.getUserList("%李%")
- 2、在sql拼接中使用通配符!
select * from user where name like "%" #{value} "%"
四、配置解析
1、核心配置文件
- mybatis-config.xml
- Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息
- Mybatis官网配置描述
配置
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
2、配置多套环境
- Mybatis可以配置成使用多种环境
不过要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境
- 学会使用配置多套运行环境
- Mybatis默认的事务管理就是JDBC,连接池:POOLED
3、属性(properties)
- 我们可以通过properties属性来实现引用配置文件
- 这些属性都是可外部配置且可动态替换,既可以在典型的java属性文件中配置,亦可通过properties元素的子元素来传递【db.properties】
- 编写一个配置文件
- db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=false username=root password=root123456
- 在核心配置文件中引入db.properties文件
<?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属性引入.properties配置文件--> <properties resource="db.properties"> <property name="username" value="root"></property> <property name="password" value="root123456"></property> </properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <!--可以通过${driver}来获取driver属性--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/yang/mapper/userMapper.xml"/> </mappers> </configuration>
- 说明
- 可以直接引入外部文件
- 可以在其中properties标签中增加一些属性配置
- 如果两个文件有相同的属性,优先使用外部的配置文件
4、属性别名
- 1、类型别名是为java类型设置一个短的名字
- 2、存在的意义仅在于用来减少类完全限定类名的冗余
- 起别名方式一:mybatis-config.xml文件
<!--可以给实体类起个别名--> <typeAliases> <typeAlias type="com.yang.po.userPo" alias="user"></typeAlias> </typeAliases>
- userMapper.xml文件
// 起别名之前 <select id="getUserList" resultType="com.yang.po.userPo"> select * from user </select> // 起别名之后 <select id="getUserList" resultType="user"> select * from user </select>
- 起别名方式二:也可以指定一个包名,mybatis会在包名下面搜索需要的javaBean,比如:扫描实体类的包,他的默认别名就为这个类的类名,首字母小写
<typeAliases> <package name="com.yang.po"/> </typeAliases>
- 也可通过在实体类上添加注解,在扫描包的的过程中讲注解配置的别名用作其中
@Data @NoArgsConstructor @AllArgsConstructor @Alias("user") public class userPo { private int id; private String name; private String pwd; }
- userMapper.xml文件
<select id="getUserList" resultType="user"> select * from user </select>
- userMapper.xml文件
// 起别名之前 <select id="getUserList" resultType="com.yang.po.userPo"> select * from user </select> // 起别名之后 <select id="getUserList" resultType="userPo"> select * from user </select>
5、设置
6、其他配置
- mybatis-generator-core
- mybatis-plus
- 通用mapper
7、映射器
- MapperRegistry:注册绑定我们的Mapper文件
- 方式一
<mappers> <mapper resource="com/yang/mapper/userMapper.xml"/> </mappers>
- 方式二
<mappers> <mapper class="com.yang.mapper.userMapper"></mapper> </mappers>
- 注意点
- 接口和他的mapper配置文件(mapper.xml文件)必须同名
- 接口和他的mapper配置文件(mapper.xml文件)必须在同一个包下
- 方式三
<mappers> <mapper class="com.yang.mapper.userMapper"></mapper> </mappers>
- 注意点
- 接口和他的mapper配置文件(mapper.xml文件)必须同名
- 接口和他的mapper配置文件(mapper.xml文件)必须在同一个包下
8、生命周期和作用域
生命周期,和作用域,是至关重要的,因为错误的使用会导致分厂严重的并发问题
SqlSessionFactoryBuilder
- 一旦创建了SqlSessionFactory,就不在需要它了
- 作用域建议放在局部变量使用
SqlSessionFactory
- 可以想象成:数据库的连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 因此SqlSessionFactory的最佳作用域是应用作用域
- 最简单的就是使用单里模式或者静态单里模式
SqlSession
- 连接到连接池的一个请求
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 用完之后需要赶紧关闭,否则资源被占用
- 这里的mapper相当于一个一个的业务
五、解决属性名和字段名不一致的问题
数据库中的字段
新建一个项目,拷贝之前的项目(mybatis-02),测试实体类字段不一致的情况
po实体情况:
@Data @NoArgsConstructor @AllArgsConstructor @Alias("user") public class userPo { private int id; private String name; private String password; }
测试出现问题:
select * from user where id=#{id} //类型处理器处理之后的sql select id,name,pwd from user where id=#{id}
1、解决方案:
- 1、在sql里起别名
select id,name,password from user where id=#{id}
2、resultMap
- 结果集映射
id name pwd id name password
<!--结果集映射--> <resultMap id="userMap" type="user"> <!--column对应数据库中的字段,property对应着实体类中的属性--> <result column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/> </resultMap> <select id="getUserById" resultMap="userMap"> select * from user where id=#{id} </select>
六、日志
1、日志工厂
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING:标准的日志工厂的实现
- NO_LOGGING
在Mybatis中具体使用哪一个日志实现,在设置中设定
1.1 STDOUT_LOGGING:标准的日志输出
- 在mybatis核心配置文件中,配置我们的日志
<settings> <!--标准的日志工厂实现--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
日志输出:
1.2 Log4j
- 什么是Log4j?
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
- 1、先导入log4j的jar包
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
- 2、创建log4j.properties配置log4j的配置文件,并进行简单配置
- 3、修改mybatis的核心配置文件(mybatis-config.xml)
<settings> <!--LOG4J--> <setting name="logImpl" value="LOG4J"/> </settings>
简单的使用
1、在使用log4j的类中,导入包import.org.apache.log4j.Logger;
2、日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(userTest.class);
3、日志级别
logger.info("info:进入了testLog4j") logger.debug("debug:进入了testLog4j") logger.error("error:进入了testLog4j")
七、分页
- 思考:为什么要分页?
- 减少数据的处理量
1、使用Limit分页
语法:select * from user limit startIndex,pageSize;
2、RowBounds分页:不在使用SQL实现分页
- 接口
List<userPo> getUserListByRowBounds();
- mapper.xml
<select id="getUserListByRowBounds" resultType="user"> select * from user </select>
- 测试
@Test public void getUserListByRowBounds(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); RowBounds rowBounds = new RowBounds(1,2); // 通过java代码层面实现分页 List<userPo> selectList = sqlSession.selectList("com.yang.mapper.userMapper.getUserListByRowBounds", "null", rowBounds); for (userPo user:selectList) { System.out.println(user); } sqlSession.close(); }
八、使用注解开发
1、注解
- 注解在接口上实现
public interface userMapper { @Select("select * from user") List<userPo> getUsers(); }
- 需要在配置文件中绑定接口(mybatis-config.xml)
<mappers> <mapper class="com.yang.mapper.userMapper"/> </mappers>
- 测试
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); userMapper mapper = sqlSession.getMapper(userMapper.class); List<userPo> userPoList = mapper.getUsers(); for (userPo user:userPoList ) { System.out.println(user); } }
2、mybatis详细的执行流程
3、使用注解实现CRUD
- 设置自动提交事务
public static SqlSession getSqlSession(){ //将openSession里的参数设置成true是,就设置成了AutoCommit = true,设置了自动提交事务 SqlSession sqlSession = sqlSessionFactory.openSession(true); return sqlSession; }
- 编写接口mapper
public interface userMapper { @Select("select * from user") List<userPo> getUsers(); @Select("select * from user where id = #{id}") userPo getUserById(@Param("id") int id); @Insert("insert into user (id,name,pwd) values(#{id},#{name},#{pwd})") Integer addUser(userPo userPo); @Delete("delete from user where id = #{id}") Integer delUser(@Param("id") int id); @Update("update user set name = #{name}, pwd = #{pwd} where id = #{id} ") Integer updateUser(@Param("id") int id,@Param("name") String name,@Param("pwd") String pwd); }
- 测试
- 注意:我们必须将接口注册绑定在配置文件中
- 关于@Param()注解
- 基本类型的参数或者String类型,需要加
- 引用类型不需要加
- 如果只有一个基本数据类型,可以忽略,但是建议加上
- 我们在SQL中引用的就是我们这里的@Param("key")中设定的key
九、Lombok
1、简介
- Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。
2、常用注解
- @Setter :注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
- @Getter :使用方法同上,区别在于生成的是getter方法。
- @ToString :注解在类,添加toString方法。
- @EqualsAndHashCode: 注解在类,生成hashCode和equals方法。
- @NoArgsConstructor: 注解在类,生成无参的构造方法。
- @RequiredArgsConstructor: 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
- @AllArgsConstructor: 注解在类,生成包含类中所有字段的构造方法。
- @Data: 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
- @Slf4j: 注解在类,生成log变量,严格意义来说是常量。
3、使用
- 在IDEA中安装Lombok插件
- 在项目中导入lombok的jar包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency>
- 在实体类上加注解即可
@Data @NoArgsConstructor @AllArgsConstructor
十、多对一处理
1、多对一概念
- 多个学生对应一个老师
- 对于学生而言,关联 多个学生关联一个老师「多对一」
- 对于老师而言,集合 一个老师,有很多学生「一对多」
2、创建teacher表和student表
CREATE TABLE `student` ( `id` int NOT NULL, `name` varchar(255) DEFAULT NULL, `tid` int DEFAULT NULL, PRIMARY KEY (`id`), KEY `fktid` (`tid`), CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; CREATE TABLE `teacher` ( `id` int NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
3、测试环境的搭建
- 导入lombok
- 新建实体类Teacher、Student
@Data public class Student { private int id; private String name; private Teacher teacher; } @Data public class Teacher { private int id; private String name; }
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件中绑定注册我们的Mapper接口或者文件
- 测试查询能否成功
4、按照查询嵌套处理
<!-- 思路: 1、查询所有的学生信息 2、根据所有的学生信息的tid,寻找对应的老师 相当于子查询 --> <select id="getStudent" resultMap="getStudent"> select * from student </select> <resultMap id="getStudent" type="Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!-- 复杂的属性,我们需要单独处理 对象:association 集合:collection--> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from teacher where id = #{tid} </select>
5、按照结果进行处理
<select id="getStudent1" resultMap="StudentTeacher"> SELECT s.id AS sid, s.`name` AS sname, t.`name` as tname FROM student s, teacher t </select> <resultMap id="StudentTeacher" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap>
十一、一对多处理
比如:一个老师拥有多个学生
对于老师而言,就是一对多的关系
1、环境搭建
- 实体类
@Data public class Teacher { private int id; private String name; private List<Student> studentList; }
@Data public class Student { private int id; private String name; private int tid; }
1、按照结果进行嵌套处理
<select id="getTeacher" resultMap="TeacherStudent"> SELECT s.id AS sid, s.`name` AS sname, t.id AS tid, t.`name` AS tname FROM student s, teacher t WHERE s.tid = t.id and t.id=#{tid} </select> <resultMap id="TeacherStudent" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <!-- 复杂的属性,我们需要单独处理 对象:association 集合:collection javaType:指定属性的类型 集合中的泛型信息,我们使用ofType获取 --> <collection property="studentList" ofType="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap>
2、按照查询嵌套处理
<select id="getTeacher2" resultMap="StudentTeacher2"> select * from teacher where id = #{tid} </select> <resultMap id="StudentTeacher2" type="Teacher"> <collection property="studentList" javaType="ArrayList" select="getStudentByTeacherId" column="id"/> </resultMap> <select id="getStudentByTeacherId" resultType="Student"> select * from student where tid = #{id} </select>
3、小结
- 关联- association【多对一】
- 集合- collection【一对多】
- javaType & ofType
- javaType用来指定实体类中属性的类型
- ofType 用来指定映射到List或者集合中的pojo类型,泛型
十二、动态SQL
什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句。
所谓动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach
1、搭建环境
- 创建blog表
CREATE TABLE `blog` ( `id` varchar(50) NOT NULL COMMENT '博客id', `title` varchar(100) NOT NULL, `author` varchar(30) NOT NULL, `create_time` datetime NOT NULL, `views` int NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 创建一个基础工程
- 导包
- 编写配置文件
- 编写实体类
@Data public class Blog { private int id; private String title; private String author; private Date createTime; private int views; }
- 编写实体类对应的Mapper接口和Mapper.XML文件
2、IF
<select id="getBlogsIf" resultType="Blog" parameterType="Map"> select * from blog <where> <if test="title != null"> and title = #{title} </if> </where> </select>
3、choose (when, otherwise)
- 相当于java中的switch。。。case。。。
- 满足一个条件就直接查询出来,不会在去匹配下一个条件。
<select id="getBlogChoose" resultType="Blog"> select * from blog <where> <choose> <when test="title != null"> and title = #{title} </when> <when test="id != null"> and id = #{id} </when> <when test="views != null"> and views = #{views} </when> <otherwise> and author = #{author} </otherwise> </choose> </where> </select>
4、trim (where, set)
where: <select id="getBlogsIf" resultType="Blog" parameterType="Map"> select * from blog <where> <if test="title != null"> and title = #{title} </if> </where> </select> set: <update id="updateBlog" parameterType="map"> update blog <set> <if test="title != null"> title = #{title}, </if> <if test="author != null"> author = #{author}, </if> <if test="views != null"> views = #{views} </if> where id = #{id} </set> </update>
5、foreach
- SQL:
<!-- select * from blog where 1=1 and (id=1 or id = 2 or id = 3) 我们需要传递一个万能的map,这个map中可以存一个集合! collection="ids" 集合名称 item="id" 遍历集合后的每一项名称 open="and (" 以什么开头 close=")" 以什么结尾 separator="or" 每一项的分隔符 --> <select id="selectBlogForeach" parameterType="map" resultType="Blog"> select * from blog <where> <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id = #{id} </foreach> </where> </select>
- 测试;
@Test public void test4(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map map = new HashMap(); List<Integer> ids = new ArrayList<>(); for (int i = 1; i < 5; i++) { ids.add(i); } map.put("ids",ids); List<Blog> blogs = mapper.selectBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } }
- 输出:
==> Preparing: select * from blog WHERE ( id = ? or id = ? or id = ? or id = ? ) ==> Parameters: 1(Integer), 2(Integer), 3(Integer), 4(Integer) <== Columns: id, title, author, create_time, views <== Row: 1, Mybatis如此简单, 郭洋, 2021-03-30 23:49:17.0, 999 <== Row: 2, Spring如此简单, 郭洋, 2021-03-30 23:49:17.0, 999 <== Row: 3, java1, 郭洋, 2021-03-30 23:49:17.0, 888 <== Row: 4, 微服务如此简单, 郭洋, 2021-03-30 23:49:17.0, 999 <== Total: 4 Blog(id=1, title=Mybatis如此简单, author=郭洋, createTime=Tue Mar 30 23:49:17 CST 2021, views=999) Blog(id=2, title=Spring如此简单, author=郭洋, createTime=Tue Mar 30 23:49:17 CST 2021, views=999) Blog(id=3, title=java1, author=郭洋, createTime=Tue Mar 30 23:49:17 CST 2021, views=888) Blog(id=4, title=微服务如此简单, author=郭洋, createTime=Tue Mar 30 23:49:17 CST 2021, views=999)
6、SQL片段
- 有的时候,我们会讲一些功能的部分抽取出来,方便复用!
- 1、使用SQL标签抽取出公共的部分
<sql id="if-title"> <if test="title != null"> and title = #{title} </if> </sql>
- 2、再需要使用的地方使用Include标签引用即可
<select id="getBlogsIf" resultType="Blog" parameterType="Map"> select * from blog <where> <include refid="if-title"></include> </where> </select>
十三、缓存
1、简介
查询: 连接数据库.. 耗资源 一次查询的结果,给他暂存在一个可以直接去到的地方!--> 内存:缓存 我们再次查询相同的数据的时候,直接走缓存,就不走数据库了
- 什么是缓存(Cache)
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统性能问题。
- 为什么使用缓存
- 减少和数据库的交互次数,减少系统开销,提高系统效率
- 什么样的数据能使用缓存
- 经常查询并且不经常改变的数据
2、Mybatis缓存
2.1、一级缓存
- 一级缓存也叫本地缓存:一次SqlSession中
- 一数据库同一次回话期间查询到的数据会放在本地的缓存中
- 以后如果需要回去相同的数据,直接从缓存中拿,没必要再去查询数据库
- 测试步骤
- 开启日志
- 测试再一次SqlSession中查询两次相同的记录
- 查看日志输出
- 缓存失效的情况
- 查询不同的东西
- 增、删、改操作,可能会改变原来的数据,所以必定会刷新缓存
- 查询不同的Mapper.xml
- 手动清理缓存!
sqlSession.clearCache();// 清理一级缓存
- 小结
- 一级缓存默认是开启的,只在一次SqlSession中有限,也就是拿到连接到关闭连接这个区间段!
2.2、二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存!
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到.二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
- 步骤
- 开启全局缓存
<!--显示的开启全局缓存--> <setting name="cacheEnabled" value="true"/>
- 在要使用二级缓存的Mapper中开启
<!--在当前Mapper.xml中使用二级缓存--> <cache/>
- 也可以自定义参数
这些属性可以通过 cache 元素的属性来修改。比如: <cache eviction="FIFO" // 清除规则 flushInterval="60000" // 时间内自动刷新缓存 size="512" // 缓存大致个数 readOnly="true"/>
- 测试
- 1、问题:我们需要讲实体类序列化!否则就会报错
- 小结
- 只要开启了二级缓存,再同一个mapper下就有效
- 所有的数据都会先放在一级缓存中;
- 只有当会话提交,或者关闭的时候,才会提交二级缓存中
3、缓存原理