狂神说Java Mybatis笔记

参考:https://blog.csdn.net/ddddeng_/article/details/106927021

MyBatis
1、简介
1.1 什么是Mybatis

MyBatis 是一款优秀的持久层框架;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2 持久化 

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

内存:断电即失。数据库(Jdbc),io文件持久化。

为什么要持久化?

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

1.3 持久层
Dao层、Service层、Controller层

完成持久化工作的代码块
层界限十分明显
1.4 为什么需要MyBatis
帮助程序员将数据存入到数据库中,方便,传统的JDBC代码太复杂了,简化,框架,自动化,不用MyBatis也可以,技术没有高低之分

优点:

简单易学,灵活

sql和代码的分离,提高了可维护性。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
提供xml标签,支持编写动态sql
2、第一个Mybatis程序
思路:搭建环境 --> 导入MyBatis --> 编写代码 --> 测试

2.1 搭建环境
新建项目

创建一个普通的maven项目

删除src目录 (就可以把此工程当做父工程了,然后创建子工程)

导入maven依赖

<!--导入依赖-->

<dependencies>
<!--mysqlq驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

 

一般情况下,我们用到的资源文件(各种xml,properites,xsd文件等)都放在src/main/resources下面,利用maven打包时,maven能把这些资源文件打包到相应的jar或者war里。

 

有时候,比如mybatis的mapper.xml文件,我们习惯把它和Mapper.java放一起,都在src/main/java下面,这样利用maven打包时,就需要修改pom.xml文件,来把mapper.xml文件一起打包进jar或者war里了,否则,这些文件不会被打包的。(maven认为src/main/java只是java的源代码路径)。


添加build

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    <ild>

 


创建一个Module

2.2 创建一个模块(可能会报中文的错误,把utf-8改为utf8)
编写mybatis的核心配置文件(mybatis-config.xml)

<?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核心配置文件-->
<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/mybatis?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>

 


编写mybatis工具类

//sqlSessionFactory --> sqlSession
public class MybatisUtils {

static SqlSessionFactory sqlSessionFactory = null;

static {
try {
//使用Mybatis第一步 :获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}

//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例.
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}

 


2.3 编写代码
实体类

Dao接口

public interface UserDao {
public List<User> getUserList();
}

接口实现类 (由原来的UserDaoImpl转变为一个Mapper配置文件)

<?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">

<!--namespace=绑定一个指定的Dao/Mapper接口-->
<mapper namespace="com.kuang.dao.UserDao">
<select id="getUserList" resultType="com.kuang.pojo.User">
select * from USER
</select>
</mapper>

编写实体类

package com.bupt.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private int id;
    private String username;

}

 

测试

import com.bupt.dao.UserDao;
import com.bupt.pojo.User;
import com.bupt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;

public class test {
    @Test
    public void test01(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        sqlSession.close();
    }

    //增删改必须提交事务
    @Test
    public void testInsert(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int i = mapper.addUser(new User(2, "梨花"));
        if(i > 0){
            System.out.println("插入成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        mapper.updateUser(new User(2,"刘雷"));
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void testDelete(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int i = mapper.deleteUser(30);
        sqlSession.commit();
        sqlSession.close();
    }
//实现模糊查询
    @Test
    public void testLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userLike = mapper.getUserLike("%张%");
        for (User user:userLike){
            System.out.println(user);
        }
        sqlSession.close();
    }

    @Test
    public void testLike1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> zhang = mapper.getUserLike1("张");
        for (User user:zhang){
            System.out.println(user);
        }
        sqlSession.close();
    }

    @Test
    public void testMap(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("id",4);
        map.put("username","王虎");
        map.put("birthday","2021-03-27");
        map.put("sex",1);
        map.put("address","北京");
        int i = mapper.insertUser(map);
        sqlSession.commit();
        sqlSession.close();
    }
}
View Code

 

注意点:

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么?

核心配置文件中注册mappers

 

junit测试

@Test
public void test(){

//1.获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//2.执行SQL
// 方式一:getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}

//关闭sqlSession
sqlSession.close();
}
View Code

 

可能会遇到的问题:

  • 配置文件没有注册
  • 绑定接口错误
  • 方法名不对
  • 返回类型不对
  • Maven导出资源问题

3、CURD
1. namespace
namespace中的包名要和Dao/Mapper接口的包名一致

2. select
选择,查询语句;

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

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

parameterType : 参数类型;

编写接口

public interface UserMapper {
//查询所有用户
public List<User> getUserList();
//插入用户
public void addUser(User user);
}

 


编写对应的mapper中的sql语句

<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into user (id,name,password) values (#{id}, #{name}, #{password})
</insert>

 


测试

@Test
public void test2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(3,"黑子","666");
mapper.addUser(user);
//增删改一定要提交事务
sqlSession.commit();

//关闭sqlSession
sqlSession.close();
}

 


注意:增删改查一定要提交事务:

sqlSession.commit();
增删改查全部流程实现

配置依赖和让资源文件能不导出

 <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>
View Code

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=root

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     <properties resource="db.properties"/>
 8     <environments default="development">
 9         <environment id="development">
10             <transactionManager type="JDBC"/>
11             <dataSource type="POOLED">
12                 <property name="driver" value="${driver}"/>
13                 <property name="url" value="${url}"/>
14                 <property name="username" value="${username}"/>
15                 <property name="password" value="${password}"/>
16             </dataSource>
17         </environment>
18     </environments>
19 <mappers>
20     <mapper resource="com/bupt/dao/UserDaoMapper.xml"></mapper>
21 </mappers>
22 </configuration>

配置类MybatisUtils 获取sqlsession

 1 package com.bupt.utils;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.InputStream;
10 
11 
12 public class MybatisUtils {
13     static SqlSessionFactory factory = null;
14     static {
15         String resource = "mybatis-config.xml";
16         try {
17             InputStream resourceAsStream = Resources.getResourceAsStream(resource);
18             factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
19 
20         } catch (IOException e) {
21             e.printStackTrace();
22         }
23     }
24     public static SqlSession getSqlSession(){
25         return factory.openSession();
26     }
27 }
View Code

实体类(默认和数据库对应)

 1 package com.bupt.pojo;
 2 
 3 import lombok.AllArgsConstructor;
 4 import lombok.Data;
 5 
 6 @Data
 7 @AllArgsConstructor
 8 public class User {
 9     private int id;
10     private String username;
11 
12 }
View Code

增删改查的接口UserDao

 1 package com.bupt.dao;
 2 
 3 import com.bupt.pojo.User;
 4 
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 public interface UserDao {
 9 
10     //查询
11     User getUserById(int id);//查询
12 
13     //insert一个用户
14     int addUser(User user);
15 
16     //更新一个用户
17     int updateUser(User user);
18 
19     //删除
20     int deleteUser(int id);
21 
22     int insertUser(Map<String,Object> map);
23 
24     //模糊查询
25     List<User> getUserLike(String name);
26     List<User> getUserLike1(String name);
27 }
View Code

增删改查的具体实现UserDaoMapper.xml

 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 <mapper namespace="com.bupt.dao.UserDao">
 6 
 7     <select id="getUserById" resultType="com.bupt.pojo.User" parameterType="int">
 8         select  * from user where id = #{id}
 9     </select>
10 
11 <!--    对象中的属性可以直接取出来-->
12     <insert id="addUser" parameterType="com.bupt.pojo.User" >
13         insert into user (id, username) values(#{id},#{username});
14     </insert>
15 
16     <update id="updateUser" parameterType="com.bupt.pojo.User">
17         update user set username=#{username} where id=#{id};
18     </update>
19     
20     <delete id="deleteUser" parameterType="int">
21         delete  from user where id=#{id};
22     </delete>
23 
24     <select id="getUserLike" parameterType="String" resultType="com.bupt.pojo.User">
25         select  * from user where username like #{name}
26     </select>
27 
28     <select id="getUserLike1" parameterType="String" resultType="com.bupt.pojo.User">
29         select  * from user where username like "%"#{name}"%"
30     </select>
31 
32     <insert id="insertUser" parameterType="map" >
33         insert into user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address});
34     </insert>
35 
36 </mapper>
View Code

别忘了在mybatis配置文件注册Mapper

<mappers>
    <mapper resource="com/bupt/dao/UserDaoMapper.xml"></mapper>
</mappers>

进行测试

 1 import com.bupt.dao.UserDao;
 2 import com.bupt.pojo.User;
 3 import com.bupt.utils.MybatisUtils;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.junit.Test;
 6 
 7 import java.util.HashMap;
 8 import java.util.List;
 9 
10 public class test {
11     @Test
12     public void test01(){
13         SqlSession sqlSession = MybatisUtils.getSqlSession();
14         UserDao mapper = sqlSession.getMapper(UserDao.class);
15         User userById = mapper.getUserById(1);
16         System.out.println(userById);
17         sqlSession.close();
18     }
19 
20     //增删改必须提交事务
21     @Test
22     public void testInsert(){
23         SqlSession sqlSession = MybatisUtils.getSqlSession();
24         UserDao mapper = sqlSession.getMapper(UserDao.class);
25         int i = mapper.addUser(new User(2, "梨花"));
26         if(i > 0){
27             System.out.println("插入成功");
28         }
29         sqlSession.commit();
30         sqlSession.close();
31     }
32 
33     @Test
34     public void updateUser(){
35         SqlSession sqlSession = MybatisUtils.getSqlSession();
36         UserDao mapper = sqlSession.getMapper(UserDao.class);
37         mapper.updateUser(new User(2,"刘雷"));
38         sqlSession.commit();
39         sqlSession.close();
40     }
41 
42     @Test
43     public void testDelete(){
44         SqlSession sqlSession = MybatisUtils.getSqlSession();
45         UserDao mapper = sqlSession.getMapper(UserDao.class);
46         int i = mapper.deleteUser(30);
47         sqlSession.commit();
48         sqlSession.close();
49     }
50 //实现模糊查询
51     @Test
52     public void testLike(){
53         SqlSession sqlSession = MybatisUtils.getSqlSession();
54         UserDao mapper = sqlSession.getMapper(UserDao.class);
55         List<User> userLike = mapper.getUserLike("%张%");
56         for (User user:userLike){
57             System.out.println(user);
58         }
59         sqlSession.close();
60     }
61 
62     @Test
63     public void testLike1(){
64         SqlSession sqlSession = MybatisUtils.getSqlSession();
65         UserDao mapper = sqlSession.getMapper(UserDao.class);
66         List<User> zhang = mapper.getUserLike1("张");
67         for (User user:zhang){
68             System.out.println(user);
69         }
70         sqlSession.close();
71     }
72 
73     @Test
74     public void testMap(){
75         SqlSession sqlSession = MybatisUtils.getSqlSession();
76         UserDao mapper = sqlSession.getMapper(UserDao.class);
77         HashMap<String, Object> map = new HashMap<>();
78         map.put("id",4);
79         map.put("username","王虎");
80         map.put("birthday","2021-03-27");
81         map.put("sex",1);
82         map.put("address","北京");
83         int i = mapper.insertUser(map);
84         sqlSession.commit();
85         sqlSession.close();
86     }
87 }
View Code

 

6. 万能Map
假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map!

UserMapper接口
//用万能Map插入用户

public void addUser2(Map<String,Object> map);

 

UserMapper.xml

<!--对象中的属性可以直接取出来 传递map的key-->
<insert id="addUser2" parameterType="map">
insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
</insert>


测试

 1 @Test
 2 public void test3(){
 3 SqlSession sqlSession = MybatisUtils.getSqlSession();
 4 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 5 HashMap<String, Object> map = new HashMap<String, Object>();
 6 map.put("userid",4);
 7 map.put("username","王虎");
 8 map.put("userpassword",789);
 9 mapper.addUser2(map);
10 //提交事务
11 sqlSession.commit();
12 //关闭资源
13 sqlSession.close();
14 }
View Code

 

  • Map传递参数,直接在sql中取出key即可! 【parameter=“map”】
  • 对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】
  • 只有一个基本类型参数的情况下,可以直接在sql中取到
  • 多个参数用Map , 或者注解!

7. 模糊查询
模糊查询这么写?

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

    <select id="getUserLike1" parameterType="String" resultType="com.bupt.pojo.User">
        select  * from user where username like #{name}
    </select>

 

 1 List<User> userList = mapper.getUserLike("%李%"); 
在sql拼接中使用通配符

 1 <select id="getUserList2" resultType="com.bupt.pojo.User"> 2 select * from user where name like "%"#{name}"%" 3 </select> 


目前程序的框架为

 

 

 pom.xml

 1 <?xml version="1.0" encoding="UTF8"?>
 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     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>org.example</groupId>
 8     <artifactId>Mybatis</artifactId>
 9     <packaging>pom</packaging>
10     <version>1.0-SNAPSHOT</version>
11     <modules>
12         <module>mybatis-1-crud</module>
13     </modules>
14     <build>
15         <resources>
16             <resource>
17                 <directory>src/main/java</directory>
18                 <includes>
19                     <include>**/*.properties</include>
20                     <include>**/*.xml</include>
21                 </includes>
22                 <filtering>true</filtering>
23             </resource>
24         </resources>
25     </build>
26     <properties>
27         <maven.compiler.source>8</maven.compiler.source>
28         <maven.compiler.target>8</maven.compiler.target>
29     </properties>
30     <dependencies>
31         <dependency>
32             <groupId>mysql</groupId>
33             <artifactId>mysql-connector-java</artifactId>
34             <version>5.1.48</version>
35         </dependency>
36         <dependency>
37             <groupId>org.mybatis</groupId>
38             <artifactId>mybatis</artifactId>
39             <version>3.5.4</version>
40         </dependency>
41         <!--junit-->
42         <dependency>
43             <groupId>junit</groupId>
44             <artifactId>junit</artifactId>
45             <version>4.12</version>
46             <scope>test</scope>
47         </dependency>
48 
49     </dependencies>
50 
51 </project>
View Code

mybatis-config.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/myschool?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/bupt/dao/UserMapper.xml"/>
    </mappers>
</configuration>
View Code

 

实体类User

package com.bupt.pojo;

import org.apache.ibatis.session.SqlSessionFactory;

import java.util.Objects;

public class User {
    private int id;
    private String name;
    private String pwd;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public User() {
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id && Objects.equals(name, user.name) && Objects.equals(pwd, user.pwd);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, pwd);
    }
}
View Code

UserDao

package com.bupt.dao;

import com.bupt.pojo.User;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public interface UserDao {
    //查询接口
    List<User> getUserList();

    User getUserById(int id);

    //插入接口
    public void addUser(User user);

    //更新一个用户
    public void updateUser(User user);

    //删除一个用户
    public void deleteUser(int id);

    //插入用户
    public void addUser2(Map<String, Object> map);

    //模糊查询用户
    List<User> getUserList2(String name);

}
View Code

UserMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--configuration核心配置文件-->
<mapper namespace="com.bupt.dao.UserDao">
    <select id="getUserList" resultType="com.bupt.pojo.User">
        select  * from USER;
    </select>

    <select id="getUserById" parameterType="int" resultType="com.bupt.pojo.User">
        select  * from USER where id=#{id};
    </select>

    <insert id="addUser" parameterType="com.bupt.pojo.User">
        insert into user (id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>

    <update id="updateUser" parameterType="com.bupt.pojo.User">
        update user set name=#{name}, pwd=#{pwd} where id=#{id};
    </update>

    <delete id="deleteUser" parameterType="int">
        delete   from user where id = #{id}
    </delete>

    <insert id="addUser2" parameterType="map">
        insert  into user(id,name) values(#{userid},#{username})
    </insert>

    <select id="getUserList2"  resultType="com.bupt.pojo.User">
        select * from user where name like "%"#{name}"%"
    </select>
</mapper>
View Code

MybatisUtils

 1 package com.bupt.utils;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.InputStream;
10 
11 public class MybatisUtils {
12     static  SqlSessionFactory build = null;
13     static {
14         String resources = "mybatis-config.xml";
15         try {
16             InputStream resourceAsStream = Resources.getResourceAsStream(resources);
17             build = new SqlSessionFactoryBuilder().build(resourceAsStream);
18 
19         } catch (IOException e) {
20             e.printStackTrace();
21         }
22     }
23     public static SqlSession getSqlSession(){
24         return build.openSession();
25     }
26 }
View Code

 

经常碰到这样的面试题目:#{}和${}的区别是什么?
 
网上的答案是:#{}是预编译处理,$ {}是字符串替换。

mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。

使用 #{} 可以有效的防止SQL注入,提高系统安全性。

sql注入指的是用户输入 or 1=1等变量导致原sql语句逻辑发生了变化,使得可以直接进入数据库,而使用预编译的方法可以让sql语句只把传入的数据当做参数进行处理

而不会改变原有sql的逻辑,preparestatement和#{}都是把变量预编译,防止sql注入。

 SQL注入详解 - myseries - 博客园 (cnblogs.com)

4、配置解析

1. 核心配置文件

  • mybatis-config.xml

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

 1 configuration(配置)
 2     properties(属性)
 3     settings(设置)
 4     typeAliases(类型别名)
 5     typeHandlers(类型处理器)
 6     objectFactory(对象工厂)
 7     plugins(插件)
 8     environments(环境配置)
 9         environment(环境变量)
10             transactionManager(事务管理器)
11             dataSource(数据源)
12     databaseIdProvider(数据库厂商标识)
13     mappers(映射器)

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

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

学会使用配置多套运行环境!

MyBatis默认的事务管理器就是JDBC ,连接池:POOLED

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

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.poperties】

编写一个配置文件

db.properties

1 driver=com.mysql.cj.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
3 username=root
4 password=root

在核心配置文件中引入

<!--引用外部配置文件-->
<properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</properties>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的

类型别名 typeAliases
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置.

意在降低冗余的全限定类名书写。

<!--可以给实体类起别名-->

<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>

 



也可以指定一个包,每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author,;若有注解,则别名为其注解值。见下面的例子:

<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>

 



在实体类比较少的时候,使用第一种方式。

如果实体类十分多,建议用第二种扫描包的方式。

第一种可以DIY别名,第二种不行,如果非要改,需要在实体上增加注解。

@Alias("author")
public class Author {
...
}

 



5. 设置 Settings
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

 

6. 其他配置
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins 插件
mybatis-generator-core
mybatis-plus
通用mapper
7. 映射器 mappers
MapperRegistry:注册绑定我们的Mapper文件;

方式一:【推荐使用】

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>

 


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

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->

<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>

 


注意点:

接口和他的Mapper配置文件必须同名
接口和他的Mapper配置文件必须在同一个包下
方式三:使用包扫描进行注入

<mappers>
<package name="com.kuang.dao"/>
</mappers>

 



8. 作用域和生命周期


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

SqlSessionFactoryBuilder:

一旦创建了SqlSessionFactory,就不再需要它了
局部变量
SqlSessionFactory:

说白了就可以想象为:数据库连接池
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建一个实例。
因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)。
最简单的就是使用单例模式或静态单例模式。
SqlSession:

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

 

8、使用注解开发
8.1 面向接口开发
三个面向区别

面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性和方法;
面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现;
接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构;
8.2 使用注解开发
注解在接口上实现

@Select("select * from user")
List<User> getUsers();

需要在核心配置文件中绑定接口

<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>

增删改查

 1 package com.bupt.dao;
 2 
 3 import com.bupt.pojo.User;
 4 import org.apache.ibatis.annotations.*;
 5 
 6 import java.util.List;
 7 import java.util.Map;
 8 
 9 public interface UserDao {
10 
11     User getUserById(int id);
12     List<User> getUserAll(Map<String,Integer> map);
13 
14     @Select("select * from user")
15     List<User> getUsers();
16 
17     @Delete("delete  from user where id=#{uid}")
18     int deleteUser(@Param("uid") int id);
19 
20     @Insert("insert into user(id,username) values(#{id},#{username})")
21     int insertUser(User user);
22 
23     @Update("update user set username=#{username} where id=#{id}")
24     int update(User user);
25 
26 }

对于增删改需要把opensession的参数设置为true,这样就等价于commit操作了,否则无法commit,及时写了commit,

    public static SqlSession getSqlSession(){
        SqlSession sqlSession = build.openSession(true);
        return  sqlSession;
    }
 1 import com.bupt.dao.UserDao;
 2 import com.bupt.pojo.User;
 3 import com.bupt.utils.MybatisUtils;
 4 import javafx.geometry.VPos;
 5 import org.apache.ibatis.session.SqlSession;
 6 import org.junit.Test;
 7 
 8 import java.util.HashMap;
 9 import java.util.List;
10 import java.util.Map;
11 import java.util.logging.Logger;
12 
13 public class TestGetUserById {
14 
15     @Test
16     public void test01(){
17         Logger logger = Logger.getLogger(String.valueOf(UserDao.class));
18         logger.info("info: 测试log4j");
19         SqlSession sqlSession = MybatisUtils.getSqlSession();
20         UserDao mapper = sqlSession.getMapper(UserDao.class);
21         User userById = mapper.getUserById(1);
22         System.out.println(userById);
23         sqlSession.close();
24     }
25 
26     @Test
27     public void test02(){
28         SqlSession sqlSession = MybatisUtils.getSqlSession();
29         UserDao mapper = sqlSession.getMapper(UserDao.class);
30         HashMap<String, Integer> stringHashMap = new HashMap<String, Integer>();
31         stringHashMap.put("startIndex",1);
32         stringHashMap.put("pagesize",2);
33         List<User> userAll = mapper.getUserAll(stringHashMap);
34         for (User user:userAll){
35             System.out.println(user);
36         }
37         sqlSession.close();
38     }
39 
40     @Test
41     public void test03(){
42         SqlSession sqlSession = MybatisUtils.getSqlSession();
43         UserDao mapper = sqlSession.getMapper(UserDao.class);
44         List<User> users = mapper.getUsers();
45         for (User user:users){
46             System.out.println(user);
47         }
48         sqlSession.close();
49     }
50 
51     @Test
52     public void test04(){
53         SqlSession sqlSession = MybatisUtils.getSqlSession();
54         UserDao mapper = sqlSession.getMapper(UserDao.class);
55         int i = mapper.deleteUser(2);
56         System.out.println(i);
57         sqlSession.close();
58     }
59     @Test
60     public void test05(){
61         SqlSession sqlSession = MybatisUtils.getSqlSession();
62         UserDao mapper = sqlSession.getMapper(UserDao.class);
63         int i = mapper.insertUser(new User(3,"test"));
64         System.out.println(i);
65         sqlSession.close();
66     }
67 
68     @Test
69     public void test06(){
70         SqlSession sqlSession = MybatisUtils.getSqlSession();
71         UserDao mapper = sqlSession.getMapper(UserDao.class);
72         int i =  mapper.update(new User(3,"test02"));
73         System.out.println(i);
74         sqlSession.close();
75     }
76 }
View Code

测试

本质:反射机制实现

底层:动态代理


MyBatis详细执行流程


8.3 注解CURD
//方法存在多个参数,所有的参数前面必须加上@Param("id")注解
@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);
关于@Param( )注解

基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型的话,可以忽略,但是建议大家都加上
我们在SQL中引用的就是我们这里的@Param()中设定的属性名
#{} 和 ${}

9、Lombok
Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。

使用步骤:

在IDEA中安装Lombok插件

在项目中导入lombok的jar包

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>

 


在程序上加注解

 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

说明:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}

 对于mybatis来说复杂的sql语句还是用配置文件来做,下面两个点是多对一一对多的介绍。推荐使用联合嵌套查询

 

10、多对一处理

多个学生一个老师;

数据库表

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

1. 测试环境搭建

  1. 导入lombok
  2. 新建实体类Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件 【方式很多,随心选】
  6. 测试查询是否能够成功

具体过程为

先在maven里面添加依赖

 1     <dependencies>
 2         <dependency>
 3             <groupId>org.projectlombok</groupId>
 4             <artifactId>lombok</artifactId>
 5             <version>1.18.16</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>junit</groupId>
 9             <artifactId>junit</artifactId>
10             <version>4.13</version>
11             <scope>test</scope>
12         </dependency>
13         <dependency>
14             <groupId>mysql</groupId>
15             <artifactId>mysql-connector-java</artifactId>
16             <version>8.0.15</version>
17         </dependency>
18         <dependency>
19             <groupId>org.mybatis</groupId>
20             <artifactId>mybatis</artifactId>
21             <version>3.5.4</version>
22         </dependency>
23         <dependency>
24             <groupId>log4j</groupId>
25             <artifactId>log4j</artifactId>
26             <version>1.2.12</version>
27         </dependency>
28 
29     </dependencies>
View Code

配置文件

db.properties

1 driver=com.mysql.cj.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/student?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
3 username=root
4 password=root
View Code

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/rzp.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.sq1.PreparedStatement=DEBUG
View Code

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     <properties resource="db.properties"/>
 8 <!--    <settings>-->
 9 <!--&lt;!&ndash;        <setting name="logImpl" value="log4j"/>&ndash;&gt;-->
10 <!--    </settings>-->
11     <typeAliases>
12         <typeAlias type="com.bupt.pojo.Teacher" alias="Teacher"/>
13         <typeAlias type="com.bupt.pojo.Student" alias="Student"/>
14         <typeAlias type="com.bupt.pojo.Student2" alias="Student2"/>
15         <typeAlias type="com.bupt.pojo.Teacher2" alias="Teacher2"/>
16     </typeAliases>
17     <environments default="development">
18         <environment id="development">
19             <transactionManager type="JDBC"></transactionManager>
20             <dataSource type="POOLED">
21                 <property name="driver" value="${driver}"/>
22                 <property name="url" value="${url}"/>
23                 <property name="username" value="${username}"/>
24                 <property name="password" value="${password}"/>
25             </dataSource>
26         </environment>
27     </environments>
28 
29 <!--  无论使用包扫描(package)还是使用class方法要注意一下
30   (1)接口和他的Mapper配置文件必须同名
31   (2)接口和他的Mapper配置文件必须在同一个包里面
32   -->
33 <!--    <mappers>-->
34 <!--        <mapper  resource="com/bupt/dao/StudentMapper.xml"/>-->
35 <!--        <mapper  class="com.bupt.dao.TeacherMapper"/>-->
36 <!--    </mappers>-->
37 
38     <mappers>
39         <package name="com.bupt.dao"/>
40     </mappers>
41 </configuration>
View Code

utils包下的MybatisUtils文件

 1 package com.bupt.utils;
 2 
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 
 8 import java.io.IOException;
 9 import java.io.InputStream;
10 
11 public class MybatisUtils {
12     static InputStream resourceAsStream = null;
13     static SqlSessionFactory build = null;
14     static {
15 
16         try {
17             String resource = "mybatis-config.xml";
18             resourceAsStream = Resources.getResourceAsStream(resource);
19             build = new SqlSessionFactoryBuilder().build(resourceAsStream);
20         } catch (IOException e) {
21             e.printStackTrace();
22         }
23     }
24 
25     public static SqlSession getSqlSession(){
26         SqlSession sqlSession = build.openSession();
27         return sqlSession;
28     }
29 }
View Code

实体类Student和Teacher

package com.bupt.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}
Student
1 package com.bupt.pojo;
2 
3 import lombok.Data;
4 
5 @Data
6 public class Teacher {
7     private int id;
8     private String name;
9 }
Teacher

Mapper接口和对应的配置文件

StudentMapper

 1 package com.bupt.dao;
 2 
 3 import com.bupt.pojo.Student;
 4 
 5 import java.util.List;
 6 
 7 public interface StudentMapper {
 8     //查询所有学生的信息,及其对应的老师的信息
 9     public List<Student> getStudent();
10     public List<Student> getStudent2();
11 }
View Code

StudentMapper.xm;

 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.bupt.dao.StudentMapper">
 6     
 7     <select id="getStudent2"  resultMap="StudentTeacher2">
 8         select s.id, s.name, t.name  tname
 9         from student s,teacher t
10         where s.tid = t.id
11     </select>
12     <resultMap id="StudentTeacher2" type="Student">
13         <result property="id" column="id"/>
14         <result property="name" column="name"/>
15         <association property="teacher" javaType="Teacher" >
16             <result property="name" column="tname"/>
17         </association>
18     </resultMap>
19     
20     
21 <!--    方式一   按照子查询的方式    -->
22     <select id="getStudent" resultMap="StudentTeacher">
23         select * from student;
24     </select>
25 
26     <resultMap id="StudentTeacher" type="Student">
27         <result property="id" column="id"/>
28         <result property="name" column="name"/>
29         <association property="teacher" column="tid" javaType="Teacher"  select="getTeacher"/>
30     </resultMap>
31 
32     <select id="getTeacher" resultType="Teacher">
33         select * from teacher where id=#{tid}
34     </select>
35 </mapper>
View Code

TeacherMapper

 1 package com.bupt.dao;
 2 
 3 import com.bupt.pojo.Teacher;
 4 import org.apache.ibatis.annotations.Param;
 5 import org.apache.ibatis.annotations.Select;
 6 
 7 public interface TeacherMapper {
 8 
 9     @Select("select * from teacher where id=#{id}")
10     Teacher getTeacher(@Param("id") int id);
11 }
View Code

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.bupt.dao.TeacherMapper">
6 
7 </mapper>
View Code

测试

 1     @Test
 2     public void test01(){
 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 
10     @Test
11     public void test02(){
12         SqlSession sqlSession = MybatisUtils.getSqlSession();
13         StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
14         for (Student student : mapper.getStudent()) {
15             System.out.println(student);
16         }
17         sqlSession.close();
18     }
19 
20     @Test
21     public void test03(){
22         SqlSession sqlSession = MybatisUtils.getSqlSession();
23         StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
24         for (Student student : mapper.getStudent2()) {
25             System.out.println(student);
26         }
27         sqlSession.close();
28     }
View Code

其中最重要的就是两种处理方式

方式一:按照查询嵌套处理

<!--
     思路:
        1. 查询所有的学生信息
        2. 根据查询出来的学生的tid寻找特定的老师 (子查询)
    -->
<select id="getStudent" resultMap="StudentTeacher">
    select * from student
</select>
<resultMap id="StudentTeacher" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性,我们需要单独出来 对象:association 集合:collection-->
    <collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
    select * from teacher where id = #{id}
</select>

方式二:按照结果嵌套处理

 1     <!--按照结果进行查询-->
 2     <select id="getStudent2" resultMap="StudentTeacher2">
 3         select s.id sid , s.name sname, t.name tname
 4         from student s,teacher t
 5         where s.tid=t.id
 6     </select>
 7     <!--结果封装,将查询出来的列封装到对象属性中-->
 8     <resultMap id="StudentTeacher2" type="student">
 9         <result property="id" column="sid"/>
10         <result property="name" column="sname"/>
11         <association property="teacher" javaType="teacher">
12             <result property="name" column="tname"></result>
13         </association>
14     </resultMap>

回顾Mysql多对一查询方式:

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

11、一对多处理

一个老师多个学生;

对于老师而言,就是一对多的关系;

1. 环境搭建

实体类

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

2. 按照结果嵌套嵌套处理(推荐使用的查询方式)

 1 <!--按结果嵌套查询-->
 2 <select id="getTeacher" resultMap="StudentTeacher">
 3     SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t
 4     WHERE s.tid = t.id AND tid = #{tid}
 5 </select>
 6 <resultMap id="StudentTeacher" type="Teacher">
 7     <result property="id" column="tid"/>
 8     <result property="name" column="tname"/>
 9     <!--复杂的属性,我们需要单独处理 对象:association 集合:collection
10     javaType=""指定属性的类型!
11     集合中的泛型信息,我们使用ofType获取
12     -->
13     <collection property="students" ofType="Student">
14         <result property="id" column="sid"/>
15         <result property="name" column="sname"/>
16         <result property="tid" column="tid"/>
17     </collection>
18 </resultMap>

子查询方式实现一对多

 1     <select id="getTeacher2" resultMap="TeacherStudent2">
 2             select * from teacher where id=#{tid}
 3     </select>
 4     <resultMap id="TeacherStudent2" type="Teacher2">
 5         <collection property="student" javaType="ArrayList" ofType="Student2" select="getTeacherStudent2" column="id"/>
 6     </resultMap>
 7     <select id="getTeacherStudent2" resultType="Student2">
 8         select *
 9         from student where tid = #{tid};
10     </select>

小结
关联 - association 【多对一】
集合 - collection 【一对多】
javaType & ofType
JavaType用来指定实体类中的类型
ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
​ 注意点:

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

面试高频

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

12、动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

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

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

搭建环境

CREATE TABLE `mybatis`.`blog`  (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '博客id',
  `title` varchar(30) NOT NULL COMMENT '博客标题',
  `author` varchar(30) NOT NULL COMMENT '博客作者',
  `create_time` datetime(0) NOT NULL COMMENT '创建时间',
  `views` int(30) NOT NULL COMMENT '浏览量',
  PRIMARY KEY (`id`)
)

创建一个基础工程

导包

编写配置文件

编写实体类

1 @Data
2 public class Blog {
3 private int id;
4 private String title;
5 private String author;
6 
7 private Date createTime;// 属性名和字段名不一致
8 private int views;
9 }

BlogMapper

 1 package com.bupt.dao;
 2 
 3 import com.bupt.pojo.Blog;
 4 
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 public interface BlogMapper {
 9 
10     int addBook(Blog blog);
11 
12     List<Blog> queryBlogIf(Map map);
13 
14     List<Blog> queryChoose(Map map);
15 
16     //更新博客
17     int updateBlog(Map map);
18 }
View Code

BlogMapper.xml

通过使用动态sql可以动态的编写sql语句,并且动态sql可以自动去除多余的and和where和,等多余的内容。

 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.bupt.dao.BlogMapper">
 6 
 7     <insert id="addBook" parameterType="blog">
 8         insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views});
 9     </insert>
10 
11     <select id="queryBlogIf" parameterType="map" resultType="blog">
12         select * from blog
13        <where>
14            <if test="title != null">
15                title = #{title}
16            </if>
17            <if test="author != null">
18                and author = #{author}
19            </if>
20        </where>
21     </select>
22 
23     <select id="queryChoose" parameterType="map" resultType="blog">
24         select * from blog
25         <where>
26             <choose>
27                 <when test="title != null">
28                     title = #{title}
29                 </when>
30                 <when test="author !=null">
31                     and author = #{author}
32                 </when>
33                 <otherwise>
34                     and view = #{views}
35                 </otherwise>
36             </choose>
37         </where>
38     </select>
39 
40     <update id="updateBlog" parameterType="map">
41         update blog
42         <set>
43             <if test="title != null">
44                 title = #{title},
45             </if>
46             <if test="author != null">
47                 author = #{author}
48             </if>
49         </set>
50         where id = #{id}
51     </update>
52 
53 
54 </mapper>

SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便服用!

使用SQL标签抽取公共部分可

<sql id="if-title-author">
<if test="title!=null">
title = #{title}
</if>
<if test="author!=null">
and author = #{author}
</if>
</sql>


在需要使用的地方使用Include标签引用即可

<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>

13、缓存
13.1 简介


查询 : 连接数据库,耗资源

​ 一次查询的结果,给他暂存一个可以直接取到的地方 --> 内存:缓存

我们再次查询的相同数据的时候,直接走缓存,不走数据库了

什么是缓存[Cache]?

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

为什么使用缓存?

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

什么样的数据可以使用缓存?

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

13.2 MyBatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大的提高查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
    •   默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
    •   二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    •   为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。

13.3 一级缓存
一级缓存也叫本地缓存:SqlSession
与数据库同一次会话期间查询到的数据会放在本地缓存中
以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
测试步骤:

开启日志

测试在一个Session中查询两次记录

    @Test
    public void test1() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);

        System.out.println("=====================================");

        User user2 =  mapper.getUserById(1);
        System.out.println(user2 == user);
    }

发现只进行了一次数据库连接

 

 

缓存失效的情况:

  1. 查询不同的东西

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

  3. 查询不同的Mapper.xml

  4. 手动清理缓存

    sqlSession.clearCache();

 

13.4 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制
    •   一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    •   如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
    •   新的会话查询信息,就可以从二级缓存中获取内容
    •   不同的mapper查询出的数据会放在自己对应的缓存(map)中
    • 一级缓存开启(SqlSession级别的缓存,也称为本地缓存)

 

二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。
步骤:

 

开启全局缓存

 

<!--显示的开启全局缓存,默认也是开启的,所以可以不写,但是写上其实是起到提醒的作用-->
<setting name="cacheEnabled" value="true"/>
在Mapper.xml中使用缓存

 

<!--在当前Mapper.xml中使用二级缓存-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>

 

  1. 测试

    1. 问题:我们需要将实体类序列化,否则就会报错

 

小结:

 

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会放在一级缓存中
  • 只有当前会话提交,或者关闭的时候,才会提交到二级缓存中

 

13.5 缓存原理

 

 

 


注意:

 

只有查询才有缓存,根据数据是否需要缓存(修改是否频繁选择是否开启)useCache=“true”

 

<select id="getUserById" resultType="user" useCache="true"> select * from user where id = #{id} </select>

 

13.6 自定义缓存-ehcache
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

 

导包

 

<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>

在mapper中指定使用我们的ehcache缓存实现

 

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

posted @ 2021-03-31 20:32  你的雷哥  阅读(1137)  评论(0编辑  收藏  举报