Mybatis

Mybatis - 图1


1、Mybatis简介

1.1 什么是Mybatis

什么是Mybatis:Mybatis是一款优秀的持久层框架,它支持定制化SQL,存储过程以及高级映射(方便写SQL)。

Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。

Mybatis可以使用简单的xml或注解来配置和映射原生类型、接口和Java的POJO(Plain Old Objects,普通老式

Java对象)为数据库中的记录。

Mybatis本是Apache的一个开源项目,2013年迁移到GitHub。

1.2 获取Mybatis

Maven仓库:https://mvnrepository.com/

  1. <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>3.5.7</version>
  6. </dependency>

Mybatis - 图2

GitHub仓库:https://github.com/

Mybatis - 图3

Mybatis - 图4

中文帮助文档:https://github.com/tuguangquan/mybatis

1.3 持久化与持久层

数据持久化

持久化就是将程序的数据在持久状态和瞬时状态转化的过程。

内存的特性:断电即失。

为什么需要持久化?

有一些对象,不能让他丢掉。内存太贵。

持久层:完成持久化工作的代码块。是界限十分明显的。

1.4 为什么需要Mybatis?

帮助程序员将数据存入数据库中。
特性:方便。传统的JDBC代码太复杂。简化,有现成的框架。自动化操作。
使用的人多!!!!


2、第一个Mybatis程序

思路:搭建环境——>导入Mybatis——>编写代码——>测试

帮助文档传送门:Mybatis帮助文档

2.1 搭建环境

搭建数据库

  1. Create database mybatis;
  2. use mybatis;
  3. create table user(
  4. id int(20) not null PRIMARY key,
  5. name VARCHAR(255) not null,
  6. pwd VARCHAR(255) not null
  7. )ENGINE=INNODB DEFAULT CHARSET=utf8;
  8. INSERT into user(id,name,pwd) VALUES
  9. (1,'张三','123456'),
  10. (2,'李四','123456'),
  11. (3,'王五','123456');

2.2 创建项目

创建一个普通的Maven项目,及时将path文件修改为正确的目录,避免占用C盘资源。

Mybatis - 图5

删除src目录,可以当做父工程使用。
Mybatis - 图6

在pom.xml文件中导入依赖

  1. <!--导入依赖-->
  2. <dependencies>
  3. <!--mysql驱动-->
  4. <dependency>
  5. <groupId>mysql</groupId>
  6. <artifactId>mysql-connector-java</artifactId>
  7. <version>5.1.47</version>
  8. </dependency>
  9. <!--mybatis-->
  10. <dependency>
  11. <groupId>org.mybatis</groupId>
  12. <artifactId>mybatis</artifactId>
  13. <version>3.5.2</version>
  14. </dependency>
  15. <!--junit-->
  16. <dependency>
  17. <groupId>junit</groupId>
  18. <artifactId>junit</artifactId>
  19. <version>4.12</version>
  20. </dependency>
  21. </dependencies>

2.3 创建模块

new——>Module——>Maven,在resources里新建一个xml配置文件
Mybatis - 图7

  1. 编写Mybatis工具类

理解:
String resource = "org/mybatis/example/mybatis-config.xml";读取配置文件

然后封装成一个工具类。

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

Mybatis - 图8

Mybatis工具类:

Mybatis - 图9

  1. public class MybatisUtils {
  2. private static SqlSessionFactory sqlSessionFactory;
  3. static {
  4. try {
  5. //使用Mybatis第一步,必须要做!!!
  6. //获取SqlSessionFactory对象
  7. String resource = "mybatis-config.xml";
  8. InputStream inputStream = Resources.getResourceAsStream(resource);
  9. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
  15. //org.apache.ibatis.session.SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
  16. public static SqlSession getSqlSession() {
  17. return sqlSessionFactory.openSession();
  18. }
  19. }
  1. 编写Mybatis的核心配置文件。

Mybatis-config.xml(注意这里测试常见报错)

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <!--configuration核心配置文件-->
  6. <configuration>
  7. <environments default="development">
  8. <environment id="development">
  9. <!--transactionManager事务管理-->
  10. <transactionManager type="JDBC"/>
  11. <dataSource type="POOLED">
  12. <property name="driver" value="com.mysql.jdbc.Driver"/>
  13. <!--防止出现问号-->
  14. <property name="url"
  15. value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8"/>
  16. <property name="username" value="root"/>
  17. <property name="password" value="123456"/>
  18. </dataSource>
  19. </environment>
  20. </environments>
  21. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  22. <mappers>
  23. <mapper resource="xleixz/dao/UserMapper.xml"/>
  24. </mappers>
  25. </configuration>

2.4 IDEA连接数据库(可选)

为了方便显示数据库内的数据,可在IDEA中连接数据库。

  1. 点击Database,点击+号,添加Data Source中的MySQL

Mybatis - 图10

  1. General中输入User(账号)、Password(密码),点击Test Connection测试连接,成功后点击Schemas

Mybatis - 图11

  1. Schemas中勾选需要用到的数据库,点击OK即可。

Mybatis - 图12

2.5 编写代码

  1. 实体类

文件:User

位置:

Mybatis - 图13

  1. //实体类
  2. public class User {
  3. private int id;
  4. private String name;
  5. private String pwd;
  6. public User() {
  7. }
  8. public User(int id, String name, String pwd) {
  9. this.id = id;
  10. this.name = name;
  11. this.pwd = pwd;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getPwd() {
  20. return pwd;
  21. }
  22. public void setPwd(String pwd) {
  23. this.pwd = pwd;
  24. }
  25. public int getId() {
  26. return id;
  27. }
  28. public void setId(int id) {
  29. this.id = id;
  30. }
  31. @Override
  32. public String toString() {
  33. return "User{" +
  34. "id=" + id +
  35. ", name='" + name + '\'' +
  36. ", pwd='" + pwd + '\'' +
  37. '}';
  38. }
  39. }
  1. Mapper接口

文件:UserDao(Dao等价于Mapper)

位置:

Mybatis - 图14

  1. //Dao等价于Mapper
  2. public interface UserDao {
  3. List<User> getUserList();
  4. }
  1. 接口实现类

由原来的UserDaoImpl转变为一个Mapper配置文件

文件:UserMapper.xml

位置:

Mybatis - 图15

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="xleixz.dao.UserDao">
  7. <!--select查询语句-->
  8. <select id="getUserList" resultType="xleixz.pojo.User">
  9. select * from mybatis.user
  10. </select>
  11. </mapper>

2.6 测试

  1. Junit测试

方式一(推荐)

  1. public class UserDaoTest<userList> {
  2. @Test
  3. public void test() {
  4. //第一步:获取SqlSession对象
  5. SqlSession sqlSession = MybatisUtils.getSqlSession();
  6. //第二步:执行SQL
  7. //方式一:
  8. UserDao userDao = sqlSession.getMapper(UserDao.class);
  9. List<User> userList = userDao.getUserList();
  10. for (User user : userList) {
  11. System.out.println(user);
  12. }
  13. //关闭SqlSession
  14. sqlSession.close();
  15. }
  16. }

Mybatis - 图16

方式二(较老,不推荐,了解)

  1. public class UserDaoTest<userList> {
  2. @Test
  3. public void test() {
  4. //第一步:获取SqlSession对象
  5. SqlSession sqlSession = MybatisUtils.getSqlSession();
  6. //第二步:执行SQL
  7. //方式一:
  8. /*UserDao userDao = sqlSession.getMapper(UserDao.class);
  9. List<User> userList = userDao.getUserList();*/
  10. //方式二:
  11. List<User> userList = sqlSession.selectList("xleixz.dao.UserDao.getUserList");
  12. for (User user : userList) {
  13. System.out.println(user);
  14. }
  15. //关闭SqlSession
  16. sqlSession.close();
  17. }
  18. }

2.7 错误分析

  1. 常见报错类型一

org.apache.ibatis.binding.BindingException: Type interface xleixz.dao.UserMapper is not known to the MapperRegistry.
MapperRegistry是什么?如何解决?

——>解决:在编写Mybatis的核心配置文件中的xml添加注册mappers配置。

  1. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  2. <mappers>
  3. <mapper resource="xleixz/dao/UserMapper.xml"/>
  4. </mappers>
  1. 常见报错类型二

The error may exist in xleixz/dao/UserMapper.xml

Mybatis - 图17

原因是Test中没有UserMapper.xml文件,可以通过手动复制到Test中,但是这样太多!太麻烦!

——>解决:手动配置资源过滤,将Build配置信息导入到pop文件中。

  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/resources</directory>
  5. <includes>
  6. <include>**/*.properties</include>
  7. <include>**/*.xml</include>
  8. </includes>
  9. <filtering>false</filtering>
  10. </resource>
  11. <resource>
  12. <directory>src/main/java</directory>
  13. <includes>
  14. <include>**/*.properties</include>
  15. <include>**/*.xml</include>
  16. </includes>
  17. <filtering>false</filtering>
  18. </resource>
  19. </resources>
  20. </build>
  1. 报错类型三

Sun Apr 17 18:17:14 CST 2022 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

——>解决:将配置文件里的useSSL=true改成useSSL=false

  1. value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8"/>

3、Mybatis增删改查实现

重点:增删改需要提交事务

Mybatis的Mapper文件中的select、insert、update、delete元素中有一个parameterType属性,用于对应的mapper接

口方法接受的参数类型。

3.1 namespace

namespace中的包名要和Mapper接口的包名一致

Mybatis - 图18

3.2 select

选择,查询语句。

id:就是对应的namespace中的方法名;

resultType:SQL语句执行的返回值;

parameterType:参数类型;

3.2.1 步骤详解

  1. 编写接口;
  1. public interface UserMapper {
  2. //根据ID查询用户
  3. User getUserById(int id);
  4. }
  1. 编写对应的Mapper中对的SQL语句;
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="xleixz.dao.UserMapper">
  7. <select id="getUserById" parameterType="int" resultType="xleixz.pojo.User">
  8. select *
  9. from mybatis.user
  10. where id = #{id}
  11. </select>
  12. </mapper>
  1. 测试。(增删改需要提交事务
  1. //增删改需要提交事务
  2. //测试插入
  3. @Test
  4. public void addUser() {
  5. SqlSession sqlSession = MybatisUtils.getSqlSession();
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. mapper.addUser(new User(4, "小雷", "123456"));
  8. //提交事务
  9. sqlSession.commit();
  10. //关闭SqlSession
  11. sqlSession.close();
  12. }

3.3 insert

注意:增删改需要提交事务

接口:这里返回值是int,int对应的是resultType的返回值类型,因为增加不需要返回值

  1. public interface UserMapper {
  2. //增加
  3. int addUser(User user);
  4. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="xleixz.dao.UserMapper">
  7. <!--对象中的属性可以直接取出来-->
  8. <insert id="addUser" parameterType="xleixz.pojo.User">
  9. insert into mybatis.user(id, name, pwd)
  10. values (#{id}, #{name}, #{pwd})
  11. </insert>
  12. </mapper>
  1. @Test
  2. public void add() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  5. userMapper.addUser(new User("xz","123456","张三","260","13888888888"));
  6. sqlSession.commit();
  7. sqlSession.close();
  8. }

3.4 update

注意:增删改需要提交事务

接口

  1. public interface UserMapper {
  2. //修改
  3. int updateUser(User user);
  4. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="xleixz.dao.UserMapper">
  7. <update id="updateUser" parameterType="xleixz.pojo.User">
  8. update mybatis.user
  9. set name = #{name},
  10. pwd = #{pwd}
  11. where id = #{id}
  12. </update>
  13. </mapper>
  1. @Test
  2. public void update() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  5. userMapper.updateUser(new User("xl", "123", "小雷学长", "8888", "18913926233"));
  6. sqlSession.commit();
  7. sqlSession.close();
  8. }

3.5 delete

注意:增删改需要提交事务

接口

  1. public interface UserMapper {
  2. //删除
  3. User deleteUser(@Param("username") String username);
  4. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--namespace绑定一个对应的Dao/Mapper接口-->
  6. <mapper namespace="xleixz.dao.UserMapper">
  7. <delete id="deleteUser" parameterType="int">
  8. delete from mybatis.user
  9. where id = #{id}
  10. </delete>
  11. </mapper>
  1. @Test
  2. public void delete(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  5. User user = userMapper.deleteUser("xl");
  6. sqlSession.commit();
  7. sqlSession.close();
  8. }

3.6 错误分析

标签不能匹配错,标签必须相对应,插入就插入,查询就查询。

resources文件夹下的xml中,mappers标签中的resource值中的不是.,而是/符号。

  1. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  2. <mappers>
  3. <mapper resource="xleixz/dao/UserMapper.xml"/>
  4. </mappers>

程序配置文件,必须符合规则!!

Mybatis - 图19
NullPointerException空指针异常报错,原因是没有注册到资源!!

输出的xml文件中存在中文乱码问题!

Maven资源无法导出问题,解决——>在Maven中加入build,详情见Maven资源无法导出


4、Map的使用

假设,实体类或数据库中的表,字段或者参数过多,应当考虑使用Map

使用MyBatis查询数据库记录时,返回类型常用的有两种:resultType和resultMap。那么两者之间有什么区别呢?

  • 如果只是返回一个值,比如说String或者int,那直接用resultType就行了;

  • 如果sql查询结果返回的列名和实体类中的字段名一致,可以使用resultType,MyBatis会自动把查询结果赋值给和字段名一致的字段。

  • 如果不一致,sql语句中可以使用别名的方式使其一致。

  • 当sql的列名和实体类的列名不一致,这时就可以使用resultMap了。

  1. //万能的Map
  2. int addUser2(Map<String, Object> map);
  1. <!--对象中的属性可以直接取出来
  2. 传递Map的key-->
  3. <insert id="addUser2" parameterType="map">
  4. insert into mybatis.user(id, name, pwd)
  5. values (#{userid}, #{username}, #{password})
  6. </insert>
  1. @Test
  2. public void addUser2() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. Map<String, Object> map = new HashMap<String,Object>();
  6. map.put("userid",5);
  7. map.put("username","Hello");
  8. map.put("password",222333);
  9. mapper.addUser2(map);
  10. //提交事务
  11. sqlSession.commit();
  12. //关闭SqlSession
  13. sqlSession.close();
  14. }

Map传递参数,直接在SQL中取出key即可!parameterType="map"

对象传递参数,直接在SQL中取出对象的属性即可!parameterType="Object"

只有 一个基本类型参数的情况,直接在SQL中取到! 省略不写

多个参数用Map!,或注解!


5、模糊查询拓展

模糊查询怎么写?

传送门:MySQL的模糊查询

在Java代码查询执行的时候,传递通配符% %

接口类

  1. public interface UserMapper {
  2. //模糊查询一个用户
  3. List<User> getUserLike(String value);
  4. }

接口实现类

  1. <!--模糊查询用户信息-->
  2. <select id="getUserLike" resultType="xleixz.pojo.User">
  3. select *
  4. from mybatis.user
  5. where name like #{value }
  6. </select>

测试类

  1. @Test
  2. public void getUserLike() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. List<User> userList = mapper.getUserLike("%李%");
  6. for (User user : userList) {
  7. System.out.println(user);
  8. }
  9. //关闭SqlSession
  10. sqlSession.close();
  11. }

Mybatis - 图20


6、XML配置解析

6.1 属性优化

6.1.1 核心配置文件

核心配置文件为:mybatis.config.xml

Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息。

XML配置(官网帮助文档)

configuration(配置)

6.1.2 环境配置(environments)

MyBatis 可以配置成适应多种环境

  • 理解:

environments标签中可以配置多个environment环境,但是默认是environments default=后的id。
若想更换默认环境,则修改default的id值即可。

  1. <!--configuration核心配置文件-->
  2. <configuration>
  3. <!--default默认的id就是默认的配置-->
  4. <environments default="development-01">
  5. <environment id="development-01">
  6. <!--这里是环境development-01-->
  7. </environment>
  8. <environment id="development-02">
  9. <!--这里是环境development-02-->
  10. </environment>
  11. </environments>

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

6.1.3 事务管理器(transactionManager)

了解即可

在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。

6.1.4 数据源(dataSource)

==了解即可

:用完可以回收。

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特

性,就必须配置数据源。

有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):

UNPOOLED – 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求

不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接

池并不重要,这个配置就很适合这种情形。

POOLED – 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的

初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然

后放置一个 JNDI 上下文的数据源引用。

重点
Mybatis默认的事物管理器就是JDBC,连接池就是POOLED。

6.1.5 属性(properties)

我们可以通过properties属性来实现引用配置文件。

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以

在 properties 元素的子元素中设置。

编写一个配置文件

db.properties

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8
  3. username=root
  4. password=123456

核心配置文件mybatis-config.xml中引入properties

注意:在xml中,所有的标签都可以规定其顺序,properties只能放在最上面

  1. <!--引入外部配置文件-->
  2. <properties resource="db.properties">
  3. <property name="username" value="root"/>
  4. <property name="password" value="123456"/>
  5. </properties>

注意:可以直接引入外部文件,也可以在其中增加一些属性配置,如果两个文件有同一字段,优先使用外部配置文件!
优先使用外部配置文件理解:当配置文件db.properties中写了username和password,核心配置文件mybatis-config.xml中的properties标签中也写了username和password,则优先使用db.propertise文件中的配置信息。

6.2 别名优化

6.2.1 类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

方式一:

原来是这样:注意resultType:

  1. <mapper namespace="xleixz.dao.UserMapper">
  2. <!--select查询语句-->
  3. <select id="getUserList" resultType="xleixz.pojo.User">
  4. select *
  5. from mybatis.user;
  6. </select>
  7. </mapper>

核心配置文件mybatis-config.xml中添加别名配置。

  1. <!--可以给实体类起别名-->
  2. <typeAliases>
  3. <typeAlias type="xleixz.pojo.User" alias="User"/><!--alias起别名-->
  4. </typeAliases>

这样接口实现类中resultType值可优化为:

  1. <mapper namespace="xleixz.dao.UserMapper">
  2. <!--select查询语句-->
  3. <select id="getUserList" resultType="User">
  4. select *
  5. from mybatis.user;
  6. </select>
  7. </mapper>

方式二:

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean ,比如:
扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!

核心配置文件mybatis-config.xml中添加别名配置。

  1. <!--可以给实体类起别名-->
  2. <typeAliases>
  3. <package name="xleixz.pojo"/>
  4. </typeAliases>

这样接口实现类中resultType值可优化为:(建议小写)

  1. <!--select查询语句-->
  2. <select id="getUserList" resultType="user">
  3. select *
  4. from mybatis.user;
  5. </select>

方法三:

若有注解,则别名为其注解值。

在实体类上方添加注解

  1. @Alias("user")
  2. public class User {
  3. }

方法总结和区别

如果实体类很多,建议使用方式二;
方式一可以DIY别名,第二种则不行。

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

6.2.2设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

设置名 描述 有效值 默认值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 true | false false (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled 是否允许单个语句返回多结果集(需要数据库驱动支持)。 true | false true
useColumnLabel 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 true | false true
useGeneratedKeys 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 true | false False
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
autoMappingUnknownColumnBehavior 指定发现自动映射目标未知列(或未知属性类型)的行为。

一个配置完整的 settings 元素的示例如下:

  1. <settings>
  2. <setting name="cacheEnabled" value="true"/>
  3. <setting name="lazyLoadingEnabled" value="true"/>
  4. <setting name="multipleResultSetsEnabled" value="true"/>
  5. <setting name="useColumnLabel" value="true"/>
  6. <setting name="useGeneratedKeys" value="false"/>
  7. <setting name="autoMappingBehavior" value="PARTIAL"/>
  8. <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  9. <setting name="defaultExecutorType" value="SIMPLE"/>
  10. <setting name="defaultStatementTimeout" value="25"/>
  11. <setting name="defaultFetchSize" value="100"/>
  12. <setting name="safeRowBoundsEnabled" value="false"/>
  13. <setting name="mapUnderscoreToCamelCase" value="false"/>
  14. <setting name="localCacheScope" value="SESSION"/>
  15. <setting name="jdbcTypeForNull" value="OTHER"/>
  16. <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
  17. </settings>

6.3 其他配置【了解即可】

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

了解即可

6.4 映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件。

方式一【推荐使用】

推荐使用resource方式:

  1. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  2. <mappers>
  3. <mapper resource="xleixz/dao/UserMapper.xml"/>
  4. </mappers>

方式二

class方式,使用class文件绑定注册:

  1. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  2. <mappers>
  3. <mapper class="xleixz.dao.UserMapper"/>
  4. </mappers>

问题注意点:

  • 接口和它的Mapper配置文件必须同名!
  • 接口和它的Mapper配置文件必须在同一包下!

方式三

package方式,使用扫描包记性注入绑定:

  1. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  2. <mappers>
  3. <package name="xleixz.dao"/>
  4. </mappers>

7、生命周期和作用域(Scope)


生命周期作用域是至关重要的,因为错误的使用会导致非常严重的并发问题

程序运行流程:
Mybatis - 图21

SqlSessionFactoryBuilder:

  • 一旦创建了SqlSessionFactory,就不在需要它了。
  • 局部变量。

SqlSessionFactory:

  • 相当于数据库连接池
  • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • 因此SqlSessionFactory的最佳作用域是应用作用域。
  • 最简单的就是使用单例模式或静态单例模式。

SqlSession

  • 连接到连接池的一个请求!
  • SqlSession的实例不是线程安全的,因此是不能被共享的,所以他的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!这个操作是十分重要的。

Mybatis - 图22
这里面的每一个Mapper,就代表一个具体的业务!


8、解决属性名和字段名不一致的问题

8.1 问题

数据库中的字段

Mybatis - 图23

新建一个项目,拷贝之前的,测试实体类字段不一致的情况。

  1. public class User {
  2. private int id;
  3. private String name;
  4. private String password;
  5. }

测试出现问题:

Mybatis - 图24

password字段为null。
原因是:

  1. select * from mybatis.user where id = #{id};
  2. -- 类型处理器
  3. select id,name,pwd from mybatis.user where id = #{id};

8.2 解决方法

  • 方法一:起别名【较为低级,不推荐】
  1. <select id="getUserById" resultType="xleixz.pojo.User">
  2. select id,name,pwd as password
  3. from mybatis.user
  4. where id = #{id};
  5. </select>

9、resultMap结果集映射

resultMap 结果集映射

  1. id name pwd
  2. id name password

结果集映射方法:

  1. <!--id对应select中的resultMap的名字,type对应映射结果集-->
  2. <resultMap id="UserMap" type="User">
  3. <!--column数据中的字段,property实体类中的属性-->
  4. <!--相同的字段可以不写,只写需要映射的字段即可。
  5. <result column="id" property="id"/>
  6. <result column="name" property="name"/>
  7. -->
  8. <result column="pwd" property="password"/>
  9. </resultMap>
  10. <!--使用resultMap类型-->
  11. <select id="getUserById" resultMap="UserMap">
  12. select *
  13. from mybatis.user
  14. where id = #{id};
  15. </select>
  • resultMap元素是 MyBatis 中最重要最强大的元素。
  • ResultMap的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
  • ResultMap最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显示地用到他们。

    • 理解:字段一样的地方可以省略不写,只写需要映射的字段即可。

10、日志

10.1 日志工厂

Mybaits:settings(设置)

如果一个数据库操作,出现了异常,需要排错。日志就是最好的助手!

以前:sout、debug;

现在:日志工厂。

Mybatis - 图25

  • SLF4J
  • LOG4J【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

在Mybatis中具体使用哪一个日志实现,在设置中设定。

核心配置文件顺序:

Mybatis - 图26

STDOUT_LOGGING标准日志输出

在Mybatis核心配置中,配置日志!

  1. <settings>
  2. <!--标准的日志工厂实现-->
  3. <setting name="logImpl" value="STDOUT_LOGGING"/>
  4. </settings>

效果:

Mybatis - 图27

10.2 log4j

Mybaits官网传送门:settings(设置)

10.2.1 什么是Log4j?

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件;
可以控制每一条日志的输出格式;
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;
通过一个配置文件来灵活地进行配置,不需要修改应用的代码。

10.2.2 配置log4j文件

  1. pom.xml中导入log4j的包。

传送门:Maven官网导log4j

  1. <!-- https://mvnrepository.com/artifact/log4j/log4j -->
  2. <dependency>
  3. <groupId>log4j</groupId>
  4. <artifactId>log4j</artifactId>
  5. <version>1.2.17</version>
  6. </dependency>
  1. 添加log4j.properties配置文件。
  1. #将等级为DEBUG的日志信息输出的位置,console为输出到控制台,file为输出到文件,console和file的定义在下面的代码
  2. log4j.rootLogger=DEBUG,console,file
  3. #控制台输出的相关设置
  4. log4j.appender.console = org.apache.log4j.ConsoleAppender
  5. log4j.appender.console.Target = System.out
  6. log4j.appender.console.Threshold=DEBUG
  7. log4j.appender.console.layout = org.apache.log4j.PatternLayout
  8. log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
  9. #文件输出的相关设置
  10. log4j.appender.file = org.apache.log4j.RollingFileAppender
  11. log4j.appender.file.File=./log/shun.log
  12. log4j.appender.file.MaxFileSize=10mb
  13. log4j.appender.file.Threshold=DEBUG
  14. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
  16. #日志输出级别
  17. log4j.logger.org.mybatis=DEBUG
  18. log4j.logger.java.sql=DEBUG
  19. log4j.logger.java.sql.Statement=DEBUG
  20. log4j.logger.java.sql.ResultSet=DEBUG
  21. log4j.logger.java.sql.PreparedStatement=DEBUG
  1. 在核心配置文件Mybatis-config.xml配置log4j为日志的实现。
  1. <settings>
  2. <setting name="logImpl" value="LOG4J"/>
  3. </settings>

10.2.3 log4j简单测试使用

  1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;,注意:包不能导错,要导Apache的。
  2. 日志对象,参数为当前类的class:【MyTest.java】
  1. static Logger logger = Logger.getLogger(UserMapperTest.class);

Mybatis - 图28

  1. 日志级别。
  1. @Test
  2. public void testLog4j(){
  3. logger.info("info:进入了testLog4j方法");
  4. logger.debug("debug:进入了testLog4j方法");
  5. logger.error("error:进入了testLog4j方法");
  6. }
  1. 运行后会自动生成log日志文件,相当于在程序中加入System.out.println(info)一样,在log日志文件可以清晰的看到日志信息。

Mybatis - 图29

10.2.4 IDEA无法打开log文件的处理方法

IDEA有的时候无法打开一些后缀的文件,可以在File-settings-Editor-File Types中添加想要打开的文件类型。

Mybatis - 图30

再次回到IDEA打开log文件, 此时IDEA会弹出如下提示,也就是安装log文件的插件,点击Install plugins安装插件之后,也就可以正常查看文件了。

Mybatis - 图31


11、分页

11.1 Limit实现分页

为什么要分页?

  • 减少数据的处理量

使用Limit分页:

  1. 语法 select * from user limit startIndex, pageSize;

startIndex为起始位置,从哪里开始查,pageSieze为每页显示多少个。

  1. select * from user limit 3;
  2. # 相当于select * from user limit 0,3;

使用Mybatis实现分页,核心为SQL。

  1. 接口
  1. List<User> getUserByLimit(Map<String, Integer> map);
  1. Mapper.xml
  1. <!--分页实现查询-->
  2. <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
  3. select *
  4. from mybatis.user limit #{startIndex},#{pageSize};
  5. </select>
  1. 测试
  1. @Test
  2. public void getUserByLimit() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. HashMap<String, Integer> map = new HashMap<String, Integer>();
  6. map.put("startIndex", 0);
  7. map.put("pageSize", 2);
  8. List<User> userList = mapper.getUserByLimit(map);
  9. for (User user : userList) {
  10. System.out.println(user);
  11. }
  12. sqlSession.close();
  13. }

11.2 【不建议使用】RowBounds实现分页

不再使用Sql实现分页

  1. 接口
  1. //RowBounds实现分页
  2. List<User> getUserByRowBounds();
  1. mapper.xml
  1. <!--RowBounds实现分页-->
  2. <select id="getUserByRowBounds" resultMap="UserMap">
  3. select *
  4. from mybatis.user;
  5. </select>
  1. 测试
  1. @Test
  2. public void getUserByRowBounds() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. //RowBounds实现
  5. RowBounds rowBounds = new RowBounds(1, 2);
  6. //通过java代码层面实现分页
  7. List<User> userList = sqlSession.selectList("xleixz.dao.UserMapper.getUserByRowBounds", null, rowBounds);
  8. for (User user : userList) {
  9. System.out.println(user);
  10. }
  11. sqlSession.close();
  12. }

11.3 分页插件

传送门:https://pagehelper.github.io/

Mybatis - 图32

了解即可,当公司的架构师需要使用时,需要知道是什么即可!


12、使用注解开发

12.1 面向接口编程

面向接口编程含义

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是

如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到

不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内

容。面向接口编程就是指按照这种思想来编程。

根本原因解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,都遵守共同的标准,使得开

会变得容易,规范性好。

关于接口的理解

接口从更深层次的理解,应是定义与实现的分离。

接口的本身反映了系统设计人员对系统的抽象理解。

接口应有两类:

  • 第一类是对一个个体的抽象,它可对应一个抽象体;
  • 第二类是对一个个体某一方面的抽象,即形成了一个抽象面。

一个个体有可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法。

面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。

接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题。更多的体现就是对系统整体的架构。

12.2 使用注解开发

  1. 注解在接口上实现
  1. public interface UserMapper {
  2. @Select("select * from user")
  3. List<User> getUsers();
  4. }
  1. 需要在核心配置文件中绑定接口
  1. <!--绑定接口-->
  2. <mappers>
  3. <mapper class="xleixz.dao.UserMapper"/>
  4. </mappers>
  1. 测试
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. //底层主要应用反射
  5. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  6. List<User> users = mapper.getUsers();
  7. for (User user : users) {
  8. System.out.println(user);
  9. }
  10. sqlSession.close();
  11. }

本质:反射机制实现。

底层:动态代理。

Mybatis - 图33


13、Mybatis执行流程

Mybatis - 图34


14、使用注解实现增删改查

14.1 注解实现增删改查

我们可以在工具类创建的时候实现自动提交事务。

==注意:==需要优化工具类return sqlSessionFactory.openSession(true);,设置自动提交事务

  1. //工具类
  2. //sqlSessionFactory 工厂模式
  3. public class MybatisUtils {
  4. private static SqlSessionFactory sqlSessionFactory;
  5. static {
  6. try {
  7. //使用Mybatis第一步,必须要做!!!
  8. //获取SqlSessionFactory对象
  9. String resource = "mybatis-config.xml";
  10. InputStream inputStream = Resources.getResourceAsStream(resource);
  11. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. public static SqlSession getSqlSession() {
  17. //openSession方法的自动提交设置为true就会自动提交了
  18. return sqlSessionFactory.openSession(true);
  19. }
  20. }

编写接口,增加注解

  1. public interface UserMapper {
  2. @Select("select * from user")
  3. List<User> getUsers();
  4. //方法存在多个参数,所有的参数前面必须加上@Param("")注解
  5. @Select("select * from user where id = #{id}")
  6. User getUserById(@Param("id") int id);
  7. //引用对象不需要写@Param("")
  8. @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
  9. int addUser(User user);
  10. @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
  11. int updateUser(User user);
  12. @Delete("delete from user where id=#{id}")
  13. int deleteUser(@Param("id") int id);
  14. }

测试类

  1. public class UserMapperTest {
  2. //注解实现查询
  3. @Test
  4. public void select(){
  5. SqlSession sqlSession = MybatisUtils.getSqlSession();
  6. //底层主要应用反射
  7. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  8. User userById = mapper.getUserById(1);
  9. System.out.println(userById);
  10. sqlSession.close();
  11. }
  12. //注解实现添加
  13. @Test
  14. public void add(){
  15. SqlSession sqlSession = MybatisUtils.getSqlSession();
  16. //底层主要应用反射
  17. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  18. mapper.addUser(new User(7,"hello","123456"));
  19. sqlSession.close();
  20. }
  21. //注解实现更新
  22. @Test
  23. public void update(){
  24. SqlSession sqlSession = MybatisUtils.getSqlSession();
  25. //底层主要应用反射
  26. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  27. mapper.updateUser(new User(6,"two","123456"));
  28. sqlSession.close();
  29. }
  30. //注解实现删除
  31. @Test
  32. public void delete(){
  33. SqlSession sqlSession = MybatisUtils.getSqlSession();
  34. //底层主要应用反射
  35. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  36. mapper.deleteUser(6);
  37. mapper.deleteUser(7);
  38. mapper.deleteUser(8);
  39. sqlSession.close();
  40. }
  41. }

==注意:==必须将接口注册到核心配置文件中!(具体见前面映射器章节)

14.2 关于@Param()注解

  • 基本类型的参数或者String类型,需要加上。
  • 引用类型不需要加。
  • 如果只有一个基本类型,可以忽略,但是建议加上。
  • 在SQL中引用的就是这里的@Param("")中设定的属性名。

14.3 #{} 和 ${}区别

#{}能够大程度上防止sql注入,用${}无法防止sql注入。

能用#{ }时尽量用#{ }


15、Lombok的使用

Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。

理解:lombok插件用于“偷懒”,相当于Alt+Insert快捷键,能自动生成无参构造,get、set、toString、hashcode、equals等方法。

缺点:缺少直观的代码,新手可能看不懂结构。等于看不到直观的get、set方法的代码。插件依赖jar包,没有jar包无法使用。

官网帮助文档传送门:下载Lombok

Mybatis - 图35

  1. 在IDEA中安装插件

  2. 导入lombok的jar包

传送门:https://mvnrepository.com/artifact/org.projectlombok/lombok

  1. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  2. <dependency>
  3. <groupId>org.projectlombok</groupId>
  4. <artifactId>lombok</artifactId>
  5. <version>1.18.22</version>
  6. <scope>provided</scope>
  7. </dependency>
  1. 在实体类上加注解即可
  1. @Getter and @Setter
  2. @FieldNameConstants
  3. @ToString
  4. @EqualsAndHashCode
  5. @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
  6. @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
  7. @Data
  8. @Builder
  9. @SuperBuilder
  10. @Singular
  11. @Delegate
  12. @Value
  13. @Accessors
  14. @Wither
  15. @With
  16. @SneakyThrows
  17. @val
  18. @var
  19. @UtilityClass

举例:

  1. @Data //无参构造,get、set、toString、hashcode、equals
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class User {
  5. private int id;
  6. private String name;
  7. private String password;
  8. }

16、多对一处理

多对一:

Mybatis - 图36

  • 多个学生,对应一个老师;
  • 对于学生而言,关联:多个学生,关联一个老师【多对一】;
  • 对于老师而言,集合:一个老师,有很多学生【一对多】。

SQL:

  1. CREATE TABLE `teacher` (
  2. `id` INT(10) NOT NULL,
  3. `name` VARCHAR(30) DEFAULT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=INNODB DEFAULT CHARSET=utf8
  6. INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
  7. CREATE TABLE `student` (
  8. `id` INT(10) NOT NULL,
  9. `name` VARCHAR(30) DEFAULT NULL,
  10. `tid` INT(10) DEFAULT NULL,
  11. PRIMARY KEY (`id`),
  12. KEY `fktid` (`tid`),
  13. CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
  14. ) ENGINE=INNODB DEFAULT CHARSET=utf8
  15. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
  16. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
  17. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
  18. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
  19. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

16.1 测试环境搭建

16.1.1 基本环境准备

  1. 在pom文件中导入依赖
  1. <!--导入依赖-->
  2. <dependencies>
  3. <!--mysql驱动-->
  4. <dependency>
  5. <groupId>mysql</groupId>
  6. <artifactId>mysql-connector-java</artifactId>
  7. <version>5.1.47</version>
  8. </dependency>
  9. <!--mybatis-->
  10. <dependency>
  11. <groupId>org.mybatis</groupId>
  12. <artifactId>mybatis</artifactId>
  13. <version>3.5.2</version>
  14. </dependency>
  15. <!--junit-->
  16. <dependency>
  17. <groupId>junit</groupId>
  18. <artifactId>junit</artifactId>
  19. <version>4.12</version>
  20. </dependency>
  21. </dependencies>
  1. Mybatis工具类
  1. //工具类
  2. //sqlSessionFactory 工厂模式
  3. public class MybatisUtils {
  4. private static SqlSessionFactory sqlSessionFactory;
  5. static {
  6. try {
  7. //使用Mybatis第一步,必须要做!!!
  8. //获取SqlSessionFactory对象
  9. String resource = "mybatis-config.xml";
  10. InputStream inputStream = Resources.getResourceAsStream(resource);
  11. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. public static SqlSession getSqlSession() {
  17. //openSession方法的自动提交设置为true就会自动提交了
  18. return sqlSessionFactory.openSession(true);
  19. }
  20. }
  1. 核心配置文件Mybatis-config.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <!--configuration核心配置文件-->
  6. <configuration>
  7. <!--引入外部配置文件-->
  8. <properties resource="db.properties">
  9. </properties>
  10. <settings>
  11. <!--标准的日志工厂实现-->
  12. <setting name="logImpl" value="STDOUT_LOGGING"/>
  13. </settings>
  14. <environments default="development">
  15. <environment id="development">
  16. <!--transactionManager事务管理-->
  17. <transactionManager type="JDBC"/>
  18. <dataSource type="POOLED">
  19. <property name="driver" value="${driver}"/>
  20. <!--防止出现问号-->
  21. <property name="url" value="${url}"/>
  22. <property name="username" value="${username}"/>
  23. <property name="password" value="${password}"/>
  24. </dataSource>
  25. </environment>
  26. </environments>
  27. <mappers>
  28. <mapper class="com.xleixz.mapper.TeacherMapper"/>
  29. <mapper class="com.xleixz.mapper.StudentMapper"/>
  30. </mappers>
  31. </configuration>
  1. properties属性文件
  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8
  3. username=root
  4. password=123456

16.1.2 环境搭建

  1. 在pomxml文件中导入Lombok依赖

    • 安装lombok插件
    • 导入jar包
  1. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  2. <dependency>
  3. <groupId>org.projectlombok</groupId>
  4. <artifactId>lombok</artifactId>
  5. <version>1.18.22</version>
  6. <scope>provided</scope>
  7. </dependency>
  1. 新建实体类Teacher,Student
  1. @Data
  2. public class Student {
  3. private int id;
  4. private String name;
  5. //学生需要关联一个老师
  6. private Teacher teacher;
  7. }
  1. @Data
  2. public class Teacher {
  3. private int id;
  4. private String name;
  5. }
  1. 建立Mapper接口
  1. public interface StudentMapper {
  2. }
  1. public interface TeacherMapper {
  2. @Select("select * from teacher where id = #{tid}")
  3. Teacher getTeacher(@Param("tid") int id);
  4. }
  1. 建立Mapper.xml文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.StudentMapper">
  6. </mapper>
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.TeacherMapper">
  6. </mapper>
  1. 在核心配置文件中绑定注册Mapper接口或文件
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <!--configuration核心配置文件-->
  6. <configuration>
  7. <!--引入外部配置文件-->
  8. <properties resource="db.properties">
  9. </properties>
  10. <settings>
  11. <!--标准的日志工厂实现-->
  12. <setting name="logImpl" value="STDOUT_LOGGING"/>
  13. </settings>
  14. <environments default="development">
  15. <environment id="development">
  16. <!--transactionManager事务管理-->
  17. <transactionManager type="JDBC"/>
  18. <dataSource type="POOLED">
  19. <property name="driver" value="${driver}"/>
  20. <!--防止出现问号-->
  21. <property name="url" value="${url}"/>
  22. <property name="username" value="${username}"/>
  23. <property name="password" value="${password}"/>
  24. </dataSource>
  25. </environment>
  26. </environments>
  27. <mappers>
  28. <mapper class="com.xleixz.mapper.TeacherMapper"/>
  29. <mapper class="com.xleixz.mapper.StudentMapper"/>
  30. </mappers>
  31. </configuration>
  1. 测试
  1. public class MyTest {
  2. public static void main(String[] args) {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
  5. Teacher teacher = mapper.getTeacher(1);
  6. System.out.println(teacher);
  7. sqlSession.close();
  8. }
  9. }

16.1.3 目录结构

Mybatis - 图37

16.2 按照查询嵌套处理

强化16.1测试环境,查询所有学生对应的老师。

修改StudentMapper.xml文件。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.StudentMapper">
  6. <!--思路:
  7. 1.查询所有的学生信息
  8. 2.根据查询的信息的tid,寻找对应的老师-->
  9. <select id="getStudent" resultMap="StudentTeacher">
  10. select *
  11. from student;
  12. </select>
  13. <resultMap id="StudentTeacher" type="Student">
  14. <result property="id" column="id"/>
  15. <result property="name" column="name"/>
  16. <!--复杂的属性需要单独处理,对象:association,集合:collection-->
  17. <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
  18. </resultMap>
  19. <select id="getTeacher" resultType="Teacher">
  20. select *
  21. from teacher
  22. where id = #{id};
  23. </select>
  24. </mapper>
  1. public class MyTest {
  2. @Test
  3. public void testStudent(){
  4. SqlSession sqlSession = MybatisUtils.getSqlSession();
  5. StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
  6. List<Student> studentList = mapper.getStudent();
  7. for (Student student : studentList) {
  8. System.out.println(student);
  9. }
  10. sqlSession.close();
  11. }
  12. }

Mybatis - 图38

16.3 按照结果嵌套处理

个人推荐使用,因为可以在SQL中调试

修改StudentMapper.xml文件。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.StudentMapper">
  6. <!--按照结果嵌套处理-->
  7. <select id="getStudent2" resultMap="StudentTeacher2">
  8. select s.id sid, s.name sname, t.name tname
  9. from student s,
  10. teacher t
  11. where s.tid = t.id;
  12. </select>
  13. <resultMap id="StudentTeacher2" type="Student">
  14. <result property="id" column="sid"/>
  15. <result property="name" column="sname"/>
  16. <association property="teacher" javaType="teacher">
  17. <result property="name" column="tname"/>
  18. </association>
  19. </resultMap>
  20. </mapper>

测试类。

  1. public class MyTest {
  2. @Test
  3. public void testStudent2(){
  4. SqlSession sqlSession = MybatisUtils.getSqlSession();
  5. StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
  6. List<Student> studentList = mapper.getStudent2();
  7. for (Student student : studentList) {
  8. System.out.println(student);
  9. }
  10. sqlSession.close();
  11. }
  12. }

Mybatis - 图39

16.4 回顾MySQL多对一查询方式

  • 子查询(按照查询嵌套处理)
  • 联表查询(按照结果嵌套处理)

17、一对多处理

比如:一个老师拥有多个学生,对于老师而言就是一对多的关系。一个老师对应多个学生。

  1. 仍然是环境搭建,清除不需要的东西。

实体类Teacher的修改:

  1. @Data
  2. public class Teacher {
  3. private int id;
  4. private String name;
  5. //一个老师拥有多个学生
  6. private List<Student> students;
  7. }

实体类Student的修改:

  1. @Data
  2. @NoArgsConstructor
  3. public class Student {
  4. private int id;
  5. private String name;
  6. private int tid;
  7. }
  1. 目录结构

Mybatis - 图40

17.1 按照结果嵌套处理

TeacherMapper.xml文件:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.TeacherMapper">
  6. <!--按结果嵌套处理(联表查询)-->
  7. <select id="getTeacher" resultMap="TeacherStudent">
  8. select s.id sid, s.name sname, t.name tname, t.id tid
  9. from student s,
  10. teacher t
  11. where s.tid = t.id
  12. and t.id = #{tid}
  13. </select>
  14. <resultMap id="TeacherStudent" type="Teacher">
  15. <result property="id" column="tid"/>
  16. <result property="name" column="tname"/>
  17. <!--JavaType - 指定属性的类型
  18. 集合中的泛型信息,使用OfType获取-->
  19. <collection property="students" ofType="Student">
  20. <result property="id" column="sid"/>
  21. <result property="name" column="sname"/>
  22. <result property="tid" column="tid"/>
  23. </collection>
  24. </resultMap>
  25. </mapper>

测试类:

  1. @Test
  2. public void test1() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
  5. Teacher teacher = mapper.getTeacher(1);
  6. System.out.println(teacher);
  7. sqlSession.close();
  8. }

17.2 按照查询嵌套处理

TeacherMapper.xml文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.TeacherMapper">
  6. <!--按子查询嵌套处理(子查询)-->
  7. <select id="getTeacher2" resultMap="TeacherStudent2">
  8. select *
  9. from teacher
  10. where id = #{tid}
  11. </select>
  12. <resultMap id="TeacherStudent2" type="Teacher">
  13. <collection property="students" column="id" javaType="ArrayList" ofType="Student"
  14. select="getTeacherByTeacherId"/>
  15. </resultMap>
  16. <select id="getTeacherByTeacherId" resultType="Student">
  17. select *
  18. from student
  19. where tid = #{tid}
  20. </select>
  21. </mapper>

测试类:

  1. @Test
  2. public void test2() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
  5. Teacher teacher = mapper.getTeacher(1);
  6. System.out.println(teacher);
  7. sqlSession.close();
  8. }

Mybatis - 图41


18、总结多对一和一对多

  1. 关联 - association(多对一)

  2. 集合 - collection(一对多)

  3. JavaType:用来指定实体类中属性的类型。

  4. OfType:用来指定映射到List或集合中的pojo类型,泛型中的约束类型。

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂。
  • 注意一对多和多对一中,属性名和字段的问题。
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j

19、动态SQL

什么是动态SQL?

动态SQL是指根据不同的条件生成不同的SQL语句。

动态 SQL 是 MyBatis 的强大特性之一。如果使用过 JDBC 或其它类似的框架,应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

19.1 环境搭建

创建一个SQL表,字段:id,title,author,create_time,views

  1. CREATE TABLE `blog` (
  2. `id` varchar(50) NOT NULL COMMENT '博客id',
  3. `title` varchar(100) NOT NULL COMMENT '博客标题',
  4. `author` varchar(30) NOT NULL COMMENT '博客作者',
  5. `create_time` datetime NOT NULL COMMENT '创建时间',
  6. `views` int(30) NOT NULL COMMENT '浏览量'
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8

创建一个基础工程

目录结构:

Mybatis - 图42

  1. pom.xml文件导包
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>Mybatis-Study</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>Mybatis-SQL</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  18. <dependency>
  19. <groupId>org.projectlombok</groupId>
  20. <artifactId>lombok</artifactId>
  21. <version>1.18.22</version>
  22. <scope>provided</scope>
  23. </dependency>
  24. </dependencies>
  25. </project>
  1. MybatisUtils工具类
  1. //工具类
  2. //sqlSessionFactory 工厂模式
  3. public class MybatisUtils {
  4. private static SqlSessionFactory sqlSessionFactory;
  5. static {
  6. try {
  7. //使用Mybatis第一步,必须要做!!!
  8. //获取SqlSessionFactory对象
  9. String resource = "mybatis-config.xml";
  10. InputStream inputStream = Resources.getResourceAsStream(resource);
  11. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. public static SqlSession getSqlSession() {
  17. //openSession方法的自动提交设置为true就会自动提交了
  18. return sqlSessionFactory.openSession(true);
  19. }
  20. }
  1. properties属性
  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8
  3. username=root
  4. password=123456
  1. 核心配置文件Mybatis-config.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <!--configuration核心配置文件-->
  6. <configuration>
  7. <!--引入外部配置文件-->
  8. <properties resource="db.properties">
  9. </properties>
  10. <settings>
  11. <setting name="logImpl" value="STDOUT_LOGGING"/>
  12. <!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 -->
  13. <setting name="mapUnderscoreToCamelCase" value="true"/>
  14. </settings>
  15. <!--可以给实体类起别名-->
  16. <typeAliases>
  17. <typeAlias type="com.xleixz.pojo.Blog" alias="Blog"/><!--alias起别名-->
  18. </typeAliases>
  19. <environments default="development">
  20. <environment id="development">
  21. <!--transactionManager事务管理-->
  22. <transactionManager type="JDBC"/>
  23. <dataSource type="POOLED">
  24. <property name="driver" value="${driver}"/>
  25. <!--防止出现问号-->
  26. <property name="url" value="${url}"/>
  27. <property name="username" value="${username}"/>
  28. <property name="password" value="${password}"/>
  29. </dataSource>
  30. </environment>
  31. </environments>
  32. <mappers>
  33. <mapper class="com.xleixz.mapper.BlogMapper"/>
  34. </mappers>
  35. </configuration>
  1. 编写实体类
  1. @Data
  2. public class Blog {
  3. private String id;
  4. private String title;
  5. private String author;
  6. private Date createTime;
  7. private int views;
  8. }
  1. 实体类对应的Mapper接口Mapper.xml文件。

接口:

  1. public interface BlogMapper {
  2. //插入数据
  3. //新增一个博客
  4. int addBlog(Blog blog);
  5. }

sql配置文件:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.xleixz.mapper.BlogMapper">
  6. <insert id="addBlog" parameterType="blog">
  7. insert into blog(id,title, author, create_time ,views)
  8. values (#{id},#{title}, #{author}, #{createTime}, #{views});
  9. </insert>
  10. </mapper>
  1. 拓展(IDUtils工具类)
  1. //抑制警告,让黄色警告不提示
  2. @SuppressWarnings("all")
  3. public class IDUtils {
  4. public static String getId() {
  5. //获取UUID,生成随机数
  6. return UUID.randomUUID().toString().replaceAll("-", "");
  7. }
  8. }
  1. 测试类(初始化数据)
  1. public class MyTest {
  2. @Test
  3. public void addBlogTest() {
  4. SqlSession sqlSession = MybatisUtils.getSqlSession();
  5. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  6. Blog blog = new Blog();
  7. blog.setId(IDUtils.getId());
  8. blog.setTitle("Mybatis");
  9. blog.setAuthor("小雷");
  10. blog.setCreateTime(new Date());
  11. blog.setViews(9999);
  12. mapper.addBlog(blog);
  13. blog.setId(IDUtils.getId());
  14. blog.setTitle("Java");
  15. mapper.addBlog(blog);
  16. blog.setId(IDUtils.getId());
  17. blog.setTitle("Spring");
  18. mapper.addBlog(blog);
  19. blog.setId(IDUtils.getId());
  20. blog.setTitle("微服务");
  21. mapper.addBlog(blog);
  22. sqlSession.close();
  23. }
  24. }

初始化数据完毕!

19.2 IF

作用:相当于SQL中的IF语句检索查询

官网定义的固定格式:if中的test为固定

  1. <select id="xxxxxxxx" resultType="Blog">
  2. SELECT * FROM BLOG WHERE xxxxx = ‘xxxxxx’
  3. <if test="title != null">
  4. AND title like #{title}
  5. </if>
  6. </select>
  1. 接口
  1. //需求1
  2. //查询博客
  3. List<Blog> queryBlogIF(Map map);
  1. Mapper.xml文件编写SQL
  1. <!--需求1:
  2. 根据作者名字和博客名字来查询博客!
  3. 如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
  4. select * from blog where title = #{title} and author = #{author}
  5. -->
  6. <select id="queryBlogIF" parameterType="map" resultType="blog">
  7. select *
  8. from blog
  9. where 1 = 1
  10. <if test="title != null">
  11. and title = #{title}
  12. </if>
  13. <if test="author != null">
  14. and author = #{author}
  15. </if>
  16. </select>
  1. 测试类
  1. @Test
  2. public void queryBlogIF() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  5. HashMap map = new HashMap();
  6. map.put("title", "Java");
  7. List<Blog> blogs = mapper.queryBlogIF(map);
  8. for (Blog blog : blogs) {
  9. System.out.println(blog);
  10. }
  11. sqlSession.close();
  12. }

根据map.put的内容,检索查询。

Mybatis - 图43

19.3 choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

  1. <select>
  2. select * from 表
  3. <where>
  4. <choose>
  5. ……
  6. </choose>
  7. <choose>
  8. and ……
  9. </choose>
  10. <otherwise>
  11. and ……
  12. </otherwise>
  13. </where>
  14. </select>

只要找到满足的<when>,下面的都不会执行,跟Switch中的case原理一样。

  1. <select id="queryBlogchoose" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <choose>
  5. <when test="title != null">
  6. title = #{title}
  7. </when>
  8. <when test="author != null">
  9. and author = #{author}
  10. </when>
  11. <otherwise>
  12. and views = #{views}
  13. </otherwise>
  14. </choose>
  15. </where>
  16. </select>

19.4 trim(where、set)

where

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们(and)、(or)去除。

  1. <select>
  2. select * from 表
  3. <where>
  4. <if title="">
  5. ……
  6. </if>
  7. <if title="">
  8. and ……
  9. </if>
  10. </where>
  11. </select>

使用where标签后SQL语句写select * from 表即可,无需写where,同时能将if标签中的andor去掉,保证字符串正确拼接。相当于select * from blog where title = #{title}

当使用where标签后,里什么都不写,它也会自动取出where。相当于select * from blog

例如:

  1. <select id="queryBlogIF" parameterType="map" resultType="blog">
  2. select *
  3. from blog
  4. <where>
  5. <if test="title != null">
  6. title = #{title}
  7. </if>
  8. <if test="author != null">
  9. and author = #{author}
  10. </if>
  11. </where>
  12. </select>

set

用于动态更新语句的类似解决方案叫做 setset 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号。

  1. <update>
  2. update 表
  3. <set>
  4. <if title = "">
  5. ……,
  6. </if>
  7. <if title = "">
  8. ……,
  9. </if>
  10. </set>
  11. where id = #{id};
  12. </update>

例如:

  1. <!--记得加上逗号-->
  2. <update id="updateBlog" parameterType="map">
  3. update blog
  4. <set>
  5. <if test="title != null">
  6. title = #{title},
  7. </if>
  8. <if test="author != null">
  9. author = #{author}
  10. </if>
  11. </set>
  12. where id = #{id};
  13. </update>

trim

set 元素等价的自定义 trim 元素。

  1. <trim prefix="SET" suffixOverrides=",">
  2. ...
  3. </trim>

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码。

19.5 foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

准备:将数据库中前三个数据的id修改为1,2,3;

需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息

  1. 接口
  1. List<Blog> queryBlogForeach(Map map);
  1. 编写SQL语句
  1. <select id="queryBlogForeach" parameterType="map" resultType="blog">
  2. select * from blog
  3. <where>
  4. <!--
  5. collection:指定输入对象中的集合属性
  6. item:每次遍历生成的对象
  7. open:开始遍历时的拼接字符串
  8. close:结束时拼接的字符串
  9. separator:遍历对象之间需要拼接的字符串
  10. select * from blog where 1=1 and (id=1 or id=2 or id=3)
  11. -->
  12. <foreach collection="ids" item="id" open="and (" close=")" separator="or">
  13. id=#{id}
  14. </foreach>
  15. </where>
  16. </select>
  1. 测试
  1. @Test
  2. public void testQueryBlogForeach(){
  3. SqlSession session = MybatisUtils.getSession();
  4. BlogMapper mapper = session.getMapper(BlogMapper.class);
  5. HashMap map = new HashMap();
  6. List<Integer> ids = new ArrayList<Integer>();
  7. ids.add(1);
  8. ids.add(2);
  9. ids.add(3);
  10. map.put("ids",ids);
  11. List<Blog> blogs = mapper.queryBlogForeach(map);
  12. System.out.println(blogs);
  13. session.close();
  14. }

19.6 SQL片段

有的时候,我们可能会将一些公共我的部分抽取出来,方便复用。

  1. 使用<SQL>标签抽取公共的部分。
  2. 在需要的地方使用<include>标签引用即可。
  1. <!--SQL片段-->
  2. <sql id="if-title-author">
  3. <if test="title != null">
  4. title = #{title}
  5. </if>
  6. <if test="author != null">
  7. and author = #{author}
  8. </if>
  9. </sql>
  10. <select id="queryBlogIF" parameterType="map" resultType="blog">
  11. select *
  12. from blog
  13. <where>
  14. <include refid="if-title-author"/>
  15. </where>
  16. </select>

注意:

  • 最好基于单表来定义SQL片段!(不要做太复杂的事情)
  • 不要存在<where>标签。

20、缓存

20.1 简介

问题:查询需要连接数据库,耗资源。

内存:一次查询的结果,给它暂存在一个可以直接取到的地方(内存),再次查询相同数据的时候,直接走缓存,就不用连接数据库了。

1、什么是缓存 [Cache]?

  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

2、为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

3、什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据。【可以使用缓存】
  • 不经常查询且经常改变的数据【不可以使用缓存】

20.2 Mybatis缓存

Mybatis包含一个非常强大的缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

Mybatis系统中默认定义了两级缓存:一级缓存二级缓存

  • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存。
  • 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

20.3 一级缓存

一级缓存也叫本地缓存:SqlSession

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中获取,没必要再去查询数据库。

测试步骤

  1. 开启日志【mybatis-config.xml】!
  1. <settings>
  2. <setting name="logImpl" value="STDOUT_LOGGING"/>
  3. </settings>
  1. 编写接口【UserMapper.java】。
  1. //根据id查询用户
  2. User queryUserById(@Param("id") int id);
  1. 接口对应的Mapper文件【UserMapper.xml】。
  1. <select id="queryUserById" resultType="user">
  2. select * from user where id = #{id}
  3. </select>
  1. 测试在一个Session中查询两次相同的记录【MyTest.java】。
  1. @Test
  2. public void test1() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. User user = mapper.queryUserById(1);
  6. System.out.println(user);
  7. System.out.println("===========");
  8. User user2 = mapper.queryUserById(1);
  9. System.out.println(user2);
  10. System.out.println(user == user2);
  11. sqlSession.close();
  12. }
  1. 查看日志输出。

Mybatis - 图44

缓存失效的情况:

  1. 查询不同的东西。

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!

Mybatis - 图45

  1. 查询不同的Mapper.xml。

  2. 手动清理缓存!

  1. //手动清理缓存
  2. sqlSession.clearCache();

Mybatis - 图46

小结:一级缓存是默认开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!

一级缓存就是一个Map,用的时候取,用完就崩掉不用了。

20.4 二级缓存

二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。

基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

工作机制:

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
  • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
  • 新的会话查询信息,就可以从二级缓存中获取内容;
  • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

测试步骤

  1. 开启全局缓存【mybatis-config.xml】。
  1. <setting name="cacheEnabled" value="true"/>
  1. 在要使用二级缓存的Mapper中开启【xxxxMapper.xml】(一般<cache/>就够了)。
  1. <!--使用二级缓存-->
  2. <cache redonly="true"/>

也可以自定义参数,官方示例查看官方文档

  1. <!--使用二级缓存-->
  2. <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
  3. <!--这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。-->
  1. 测试

报错问题:需要将实体类序列化!!!否则就会报错。

解决:在<cache/>标签中加入redonly=true即可。

  1. @Test
  2. public void test1() {
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. SqlSession sqlSession2 = MybatisUtils.getSqlSession();
  5. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  6. User user = mapper.queryUserById(1);
  7. System.out.println(user);
  8. sqlSession.close();
  9. /*二级缓存*/
  10. UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
  11. User user2 = mapper2.queryUserById(1);
  12. System.out.println(user2);
  13. System.out.println(user == user2);
  14. sqlSession2.close();
  15. }

当第一次缓存关闭后,会存入二级缓存,无需再查询数据库。

Mybatis - 图47

小结:

只要开启了二级缓存,在同一个Mapper下就有效。

所有的数据都会先放在一级缓存中;

只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中。

20.5 缓存原理

Mybatis - 图48

20.6 自定义缓存EhCache

Ehcache是一种广泛使用的java分布式缓存,用于通用缓存;

现在使用较少,目前已经广泛使用Redis缓存

需要:要在应用程序中使用Ehcache,需要引入依赖的jar包【pom.xml】。

  1. <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
  2. <dependency>
  3. <groupId>org.mybatis.caches</groupId>
  4. <artifactId>mybatis-ehcache</artifactId>
  5. <version>1.1.0</version>
  6. </dependency>
  1. 在Mapper.xml中加入缓存配置。
  1. <cache type = “org.mybatis.caches.ehcache.EhcacheCache” />
  1. 编写ehcache.xml文件,如果在加载时未找到/ehcache.xml资源或出现问题,则将使用默认配置。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
  4. updateCheck="false">
  5. <!--
  6. diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
  7. user.home – 用户主目录
  8. user.dir – 用户当前工作目录
  9. java.io.tmpdir – 默认临时文件路径
  10. -->
  11. <diskStore path="./tmpdir/Tmp_EhCache"/>
  12. <defaultCache
  13. eternal="false"
  14. maxElementsInMemory="10000"
  15. overflowToDisk="false"
  16. diskPersistent="false"
  17. timeToIdleSeconds="1800"
  18. timeToLiveSeconds="259200"
  19. memoryStoreEvictionPolicy="LRU"/>
  20. <cache
  21. name="cloud_user"
  22. eternal="false"
  23. maxElementsInMemory="5000"
  24. overflowToDisk="false"
  25. diskPersistent="false"
  26. timeToIdleSeconds="1800"
  27. timeToLiveSeconds="1800"
  28. memoryStoreEvictionPolicy="LRU"/>
  29. <!--
  30. defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
  31. -->
  32. <!--
  33. name:缓存名称。
  34. maxElementsInMemory:缓存最大数目
  35. maxElementsOnDisk:硬盘最大缓存个数。
  36. eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  37. overflowToDisk:是否保存到磁盘,当系统当机时
  38. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  39. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  40. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  41. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  42. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
  43. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  44. clearOnFlush:内存数量最大时是否清除。
  45. memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
  46. FIFO,first in first out,这个是大家最熟的,先进先出。
  47. LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
  48. LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  49. -->
  50. </ehcache>

21、项目:Mybatis【模板】

  1. 在【pom.xml】文件中导入依赖jar包配置Maven静态资源过滤 ```xml mysql mysql-connector-java 5.1.46 org.mybatis mybatis 3.5.2 junit junit 4.12 org.projectlombok lombok 1.18.22

src/main/resources /*.properties /.xml false src/main/java **/.properties */.xml false

  1. 2.
  2. 在**resources文件夹中**创建数据库驱动属性【db.properties
  3. ```properties
  4. driver=com.mysql.jdbc.Driver
  5. url=jdbc:mysql://localhost:3306/tingcc?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8
  6. username=root
  7. password=123456
  1. utils文件夹中创建工具类【MybatisUtils.java】 ```java //工具类 //sqlSessionFactory 工厂模式

public class MybatisUtils {

  1. private static SqlSessionFactory sqlSessionFactory;
  2. static {
  3. try {
  4. //使用Mybatis第一步,必须要做!!!
  5. //获取SqlSessionFactory对象
  6. String resource = "mybatis-config.xml";
  7. InputStream inputStream = Resources.getResourceAsStream(resource);
  8. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. public static SqlSession getSqlSession() {
  14. return sqlSessionFactory.openSession(true);
  15. }

}

  1. 4.
  2. 在**resources文件夹**中创建**mybatis核心配置文件**【Mybatis-config.xml
  3. ```xml
  4. <?xml version="1.0" encoding="UTF-8" ?>
  5. <!DOCTYPE configuration
  6. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  7. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  8. <!--configuration核心配置文件-->
  9. <configuration>
  10. <!--引入外部配置文件-->
  11. <properties resource="db.properties">
  12. </properties>
  13. <typeAliases>
  14. <package name="com.xleixz.pojo"/>
  15. </typeAliases>
  16. <environments default="development">
  17. <environment id="development">
  18. <!--transactionManager事务管理-->
  19. <transactionManager type="JDBC"/>
  20. <dataSource type="POOLED">
  21. <property name="driver" value="${driver}"/>
  22. <!--防止出现问号-->
  23. <property name="url" value="${url}"/>
  24. <property name="username" value="${username}"/>
  25. <property name="password" value="${password}"/>
  26. </dataSource>
  27. </environment>
  28. </environments>
  29. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  30. <mappers>
  31. <mapper resource="com/xleixz/mapper/UserMapper.xml"/>
  32. </mappers>
  33. </configuration>
  1. pojo文件夹中创建一个实体类【User.java】 ```java public class User {

    private String username; private String pwd; private String realname; private String blance; private String MobilePhone;

    public User() { }

    public User(String username, String password, String realname, String blance, String mobilePhone) {

    1. this.username = username;
    2. this.pwd = password;
    3. this.realname = realname;
    4. this.blance = blance;
    5. MobilePhone = mobilePhone;

    }

  1. public String getUsername() {
  2. return username;
  3. }
  4. public void setUsername(String username) {
  5. this.username = username;
  6. }
  7. public String getPassword() {
  8. return pwd;
  9. }
  10. public void setPassword(String password) {
  11. this.pwd = password;
  12. }
  13. public String getRealname() {
  14. return realname;
  15. }
  16. public void setRealname(String realname) {
  17. this.realname = realname;
  18. }
  19. public String getBlance() {
  20. return blance;
  21. }
  22. public void setBlance(String blance) {
  23. this.blance = blance;
  24. }
  25. public String getMobilePhone() {
  26. return MobilePhone;
  27. }
  28. public void setMobilePhone(String mobilePhone) {
  29. MobilePhone = mobilePhone;
  30. }
  31. @Override
  32. public String toString() {
  33. return "User{" +
  34. "username='" + username + '\'' +
  35. ", password='" + pwd + '\'' +
  36. ", realname='" + realname + '\'' +
  37. ", blance='" + blance + '\'' +
  38. ", MobilePhone='" + MobilePhone + '\'' +
  39. '}';
  40. }

}

  1. 6.
  2. 在**mapper文件夹**中创建**实体类接口**【UserMapper.java
  3. ```java
  4. public interface UserMapper {
  5. //查询
  6. User getUser(@Param("username") String username);
  7. //增加
  8. int addUser(User user);
  9. //修改
  10. int updateUser(User user);
  11. //删除
  12. int deleteUser(@Param("username") String username);
  13. }
  1. mapper文件夹中创建实体类接口配置文件【UserMapper.xml】 ```xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE mapper
    1. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    2. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  1. <resultMap id="u" type="user">
  2. <result column="password" property="pwd"/>
  3. </resultMap>
  4. <select id="getUser" parameterType="String" resultMap="u">
  5. select *
  6. from t_user
  7. where username = #{username}
  8. </select>
  9. <insert id="addUser" parameterType="user">
  10. insert into t_user(username, password, realname, blance, MobilePhone)
  11. values (#{username}, #{password}, #{realname}, #{blance}, #{MobilePhone})
  12. </insert>
  13. <update id="updateUser" parameterType="user">
  14. update t_user
  15. set password=#{password},
  16. realname=#{realname},
  17. blance=#{blance},
  18. MobilePhone=#{MobilePhone}
  19. where username = #{username}
  20. </update>
  21. <delete id="deleteUser" parameterType="String">
  22. delete
  23. from t_user
  24. where username = #{username}
  25. </delete>

  1. 8.
  2. 在**核心配置文件**【Mybatis-config.xml】中**绑定接口配置文件**【UserMapper.xml
  3. ```xml
  4. <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!-->
  5. <mappers>
  6. <mapper resource="com/xleixz/mapper/UserMapper.xml"/>
  7. </mappers>


Mybatis - 图49

  1. test文件夹中创建测试类【MyTest.java】

    1. public class MyTest {
    2. @Test
    3. public void select() {
    4. SqlSession sqlSession = MybatisUtils.getSqlSession();
    5. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    6. User user = userMapper.getUser("xl");
    7. System.out.println(user);
    8. sqlSession.close();
    9. }
    10. @Test
    11. public void add() {
    12. SqlSession sqlSession = MybatisUtils.getSqlSession();
    13. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    14. User user = new User("zs", "123456", "张三", "260", "13888888888");
    15. userMapper.addUser(user);
    16. sqlSession.commit();
    17. sqlSession.close();
    18. }
    19. @Test
    20. public void update() {
    21. SqlSession sqlSession = MybatisUtils.getSqlSession();
    22. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    23. userMapper.updateUser(new User("zs", "zs123", "张三(2)", "8888", "18913926233"));
    24. sqlSession.commit();
    25. sqlSession.close();
    26. }
    27. @Test
    28. public void delete() {
    29. SqlSession sqlSession = MybatisUtils.getSqlSession();
    30. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    31. userMapper.deleteUser("zs");
    32. sqlSession.commit();
    33. sqlSession.close();
    34. }
    35. }

结构:

Mybatis - 图50

完结! 2022-04-23