mybatis3学习笔记

个人学习笔记mybatis

1、简介

中文文档:https://mybatis.org/mybatis-3/zh/getting-started.html

1.1、什么是MyBatis:

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

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

  • maven仓库:

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

1.2、持久层:

数据持久化:

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

2、HelloMybatis

  • 搭建环境(数据库)——》导入mybatis——》编写代码——》测试!

  • 项目结构:

  1. 新建一个maven项目,删除src目录,建立module项目,导入maven依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    </dependency>
  2. 创建一个子模块,编写mybatis的核心配置文件和编写mybatis的工具类:

    • mybatis-config.xml:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">

    <configuration>

    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatistest?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    </dataSource>
    </environment>
    </environments>

    <mappers>
    <mapper resource="UserMapper.xml"/>
    </mappers>
    </configuration>
    • MybatisUtils工具类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package com.aaron.utils;

    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;

    import java.io.IOException;
    import java.io.InputStream;

    public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    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 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession();
    }

    }

2.1、编写代码:

  • 实体类User:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    package com.aaron.pojo;

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

    public User() {
    }

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

    public int getId() {
    return id;
    }

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

    public String getName() {
    return name;
    }

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

    public String getPwd() {
    return pwd;
    }

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package com.aaron.dao;

    import com.aaron.pojo.User;

    import java.util.List;

    public interface UserDao {
    public List<User> getUserList();
    }
  • 接口实现类,由原来的UserDaoImpl.java变成了UserMapper.xml文件了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?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">

    //这里的id就像接口里要实现的方法名,resultType是执行sql语句后的返回值类型。里面写好sql语句。
    <mapper namespace="com.aaron.dao.UserDao">
    <select id="getUserList" resultType="com.aaron.pojo.User">
    select * from mybatistest.user;
    </select>
    </mapper>
  • 测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package com.aaron.dao;

    import com.aaron.pojo.User;
    import com.aaron.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;

    import java.util.List;

    public class UserDaoTest {

    @Test
    public void test(){
    //第一步,获得SqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //执行SQL
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.getUserList();
    for (User user : userList) {
    System.out.println(user);
    }
    //关闭SqlSession
    sqlSession.close();
    }

    }
  • 测试结果:

    image-20200721203459936

3、CRUD

C:Create增加,R:Retrieve查询,U:Update修改,D:Delete删除。

3.1、namespace:

namespace中的包名要和dao/mapper接口的包名一致;

  • UserMapper.xml:

image-20200723124353020

3.2、select、insert、update、delete:

写起来很简单,之前的pojo实体类和utils工具类以及mybatis-config.xml配置文件都不用改变。主要改变的是dao层的接口类和UserMapper.xml配置文件:

image-20200723130502497

  • dao层里面的接口UserDao.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.aaron.dao;

    import com.aaron.pojo.User;

    import java.util.List;

    public interface UserDao {
    //获取全部用户
    public List<User> getUserList();

    //根据id查询用户
    User getUser(int userId);

    //插入用户
    Integer addUser(User user);

    //修改用户
    Integer updateUser(User user);

    //根据id删除用户
    Integer deleteUser(int id);
    }
  • UserMapper.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    <mapper namespace="com.aaron.dao.UserDao">
    <select id="getUserList" resultType="com.aaron.pojo.User">
    select * from mybatistest.user;
    </select>

    <select id="getUser" parameterType="int" resultType="com.aaron.pojo.User">
    select * from mybatistest.user where id = #{userId}
    </select>

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

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

    <select id="deleteUser">
    delete from mybatistest.user where id=#{id}
    </select>
    </mapper>
  • 测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    package com.aaron.dao;

    import com.aaron.pojo.User;
    import com.aaron.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;

    import java.util.List;

    public class UserDaoTest {

    @Test
    public void test(){
    //第一步,获得SqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //执行SQL
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.getUserList();
    for (User user : userList) {
    System.out.println(user);
    }
    //关闭SqlSession
    sqlSession.close();
    }

    @Test
    public void test1(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserDao mapper = sqlSession.getMapper(UserDao.class);
    User user = mapper.getUser(4);
    System.out.println(user);
    sqlSession.close();
    }

    //增删改需要提交事务
    @Test
    public void test2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    Integer flag = mapper.addUser(new User(7,"哈哈","12345"));
    System.out.println(flag);
    sqlSession.commit();

    sqlSession.close();
    }

    @Test
    public void test3(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    Integer flag = mapper.updateUser(new User(4,"夏天","123dssdd"));
    System.out.println(flag);
    sqlSession.commit();
    sqlSession.close();
    }

    @Test
    public void test4(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    Integer flag = mapper.deleteUser(7);
    System.out.println(flag);
    sqlSession.commit();
    sqlSession.close();
    }
    }

3.3、map传递参数:

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

  • 实体类:
1
2
//传递map参数
User addUser2(Map<String,Object> map);
  • 配置文件UserMapper.xml:
1
2
3
<select id="addUser2" parameterType="map">
insert into mybatistest.user (id, name, pwd) values (#{id},#{name},#{pwd});
</select>
  • 测试时:
1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test5(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id",7);
map.put("name","夏天天1号");
map.put("pwd","123456");
mapper.addUser2(map);
sqlSession.commit();
sqlSession.close();
}

3种情况:

  • Map传递参数,直接在sql中取出key即可!
  • 对象传递参数,直接在sql中取对象的属性即可。
  • 只有一个基本类型参数的,可以直接在sql中取到。

3.4、模糊查询:

  1. java执行代码的时候,传递通配符% %

    image-20200723144008235

  2. sql注入问题一览:

    1
    2
    3
    4
    select * from user where id = ?;
    select * from user where id = 1;

    select * from user where id = 1 or 1 = 1;
  3. 模糊查询实例:

    • 实体类的方法:

      1
      2
      //模糊查询,根据名字
      List<User> getUserLike(String name);
    • 配置文件UserMapper.xml:

      1
      2
      3
      <select id="getUserLike" resultType="com.aaron.pojo.User">
      select * from mybatistest.user where name like #{name}
      </select>
    • 测试类:

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

4、配置之属性优化

注意里面的属性书写是有先后之分的:(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)”。注意哈,这都是写在mybatis-config.xmll文件中的。

4.1、核心配置mybatis-config.xml:

  • mybatis-config.xml配置文件中包含了会深深影响mybatis行为的设置和属性信息:

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

4.2、环境配置(environment):

mybatis可以配置成适应多种环境。

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

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

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

4.3、properties(属性):

我们可以通过properti属性来实现引用配置文件。这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】

  1. 编写db.properties配置文件:

    1
    2
    3
    4
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatistest?useSSL=true&useUnicode=true&characterEncoding=UTF-8
    username=root
    password=root
  2. 在核心配置文件mybatis-config.xml中引入:

    • 直接引入外部文件:
    1
    <properties resource="db.properties"/>
    • 在其中可以增加属性配置:
    1
    2
    3
    <properties resource="db.properties">
    <property name="password" value="12345"/>
    </properties>
    • 如果既有外部配置文件,又配置了相同的属性,优先使用外部配置文件里面的属性。

4.4、类型别名(typeAliases):

  1. 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
1
2
3
<typeAliases>
<typeAlias type="com.aaron.pojo.User" alias="user"/>
</typeAliases>

那么在UserMapper.xml中使用时:

image-20200723182221949

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

    1
    2
    3
    4
    5
    <typeAliases>
    <package name="com.aaron.pojo.User"/>
    </typeAliases>

    使用时就是parameterType="user",类名的首字母小写即可。

总结说明:在实体类比较少的时候,使用第一种方式。如果实体类十分多,建议使用第二种。第一种可以diy别名,第二种则不行,如果非要改,需要在实体上增加注解。

1
2
3
@Alias("user1")
public class User {
...
  • 别名参考:下面是一些为常见的 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
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

4.5、设置(settings):

image-20200723200701175

image-20200723200728188

1
2
3
4
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>

4.6、其他配置:

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件):
    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

4.7、映射器(mappers):

我们需要告诉 MyBatis 到哪里去找到 SQL 映射语句,就是UserMapper.xml这样的文件里定义的。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。

MapperRegistry:注册绑定我们的Mapper文件。每一个Mapper.xml都需要在mybatis的核心配置文件里面注册。

  • 方式一:

    1
    2
    3
    <mappers>
    <mapper resource="com/aaron/dao/UserMapper.xml"/>
    </mappers>
  • 方式二:

    1
    2
    3
    <mappers>
    <mapper class="com.aaron.dao.UserMapper"/>
    </mappers>
    • 使用这种方式的注意点:
      • 接口和它的Mapper配置文件必须同名。
      • 接口和他的Mapper配置文件必须在同一包下。
  • 方式三:

    1
    2
    3
    4
    <!-- 将包内的映射器接口实现全部注册为映射器,-->
    <mappers>
    <package name="com.aaron.dao"/>
    </mappers>
    • 使用这种方式的注意点:
      • 接口和它的Mapper配置文件必须同名。
      • 接口和他的Mapper配置文件必须在同一包下。

4.8、生命周期与作用域:

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

SqlSessionFactoryBuilder:

  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。所以可以将其设置为局部变量。

SqlSessionFactory:

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

SqlSession:

  • 就像连接到连接池的一个请求
  • 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

image-20200723212754942

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

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

数据库中的字段:

image-20200723204731043

当你的实体类pojo如果和数据库中的字段不一致时。

例如:你在实体类里面将数据库的pwd写成password,那么有可能查出的user里面password=null。

image-20200724073143227

解决方法:

5.1、起别名

1
select id,name,pwd as password from mybatistest.user;

5.2、resultMap:

结果集映射。

1
2
id   name   pwd
id name password

使用方法:

image-20200724074046862

1
2
3
4
5
6
7
8
9
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password from some_table where id = #{id}
</select>

6、日志

6.1、日志工厂:

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

曾经的实现方法:sout、debug。

现在的方法:日志工厂。

image-20200724093712912

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

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

STDOUT_LOGGING:标准日志输出

在mybatis核心配置文件中,配置我们的日志!

1
2
3
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

image-20200724095336391

6.2、LOG4J讲解:

什么是LOG4J?

  • Log4j是Apache的一个开放源代码项目bai,通过du使用Log4j,我们可以控制zhi日志信息输送的目的地是控制台、文件。。。

  • 我们也可以控制每一条日志的输出格式;

  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

  1. 先导入log4j的包:

    1
    2
    3
    4
    5
    6
    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
  2. 在CLASSPATH下建立log4j.properties。内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
    log4j.rootLogger=DEBUG,console,file

    #控制台输出的相关设置
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=【%c】-%m%n

    #文件输出的相关设置
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=./log/kuang.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=【%p】【%d{yy-MM-dd}】【%c】%m%n

    #日志输出级别
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sql.PreparedStatement=DEBUG
  3. 在mybatis的核心配置文件中,配置log4j为日志的实现:

    1
    2
    3
    <settings>
    <setting name="logImpl" value="LOG4J"/>
    </settings>
  4. log4j的使用,测试运行查询方法:

    image-20200724114147100

log4j的简单使用:

  1. 在要使用的Log4j的类中,导入包import org.apache.log4j.Logger;

  2. 日志对象,参数为当前类的class

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.mucfc;
    import org.apache.log4j.Logger;

    public class Test {
    private static Logger logger = Logger.getLogger(Test.class);

    public static void main(String[] args) {
    logger.debug("This is debug message.");
    logger.info("This is info message.");
    logger.error("This is error message.");
    }

    }
  3. 日志级别:

    1
    2
    3
    logger.debug("This is debug message."); 
    logger.info("This is info message.");
    logger.error("This is error message.");

7、分页

思考:为什么要分页?

  • 减少数据的处理量

7.1、使用Limit分页:

sql语句:select * from user limit startIndex,pageSize;

数据库的下标也是从0开始的。假设:

1
2
3
select * from user limit 0,2;
select * from user limit 2,2;
.....

7.2、RowBounds分页:

不建议使用。

7.3、分页插件:

8、使用注解开发

  1. 注解在接口上实现:

    1
    2
    3
    //获取所有的用户
    @Select("select * from user")
    List<User> getUserList();
  2. 需要在mybatis-config.xml核心配置文件中绑定接口:

    1
    2
    3
    4
    <!--绑定接口-->
    <mappers>
    <mapper class="com.aaron.dao.UserDao"/>
    </mappers>

本质:反射机制。

底层:动态代理。

8.1、CRUD:

1
2
3
//根据id和name查询用户
@Select("select * from user where id = #{id} and name = #{name}")
User getUserBy(@Param("id") int id, @Param("name") String name);
  • 关于@Param()注解:
    • 基本类型的参数或者String类型,需要加上。
    • 引用类型不需要加。
    • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上。
    • 我们在sql中引用的就是我们这里的@Param(“”)中设定的属性名。

9、Lombok的使用:

Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。Lombok也存在一定风险,在一些开发工具商店中没有Project Lombok支持选择。 IDE和JDK升级存在破裂的风险,并且围绕项目的目标和实施存在争议。

  1. 在IDEA中安装lombok的插件。

  2. 在项目中导入lombok的jar包。

    1
    2
    3
    4
    5
    6
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    </dependency>
  3. lombok的注解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Setter :注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
    @Getter :使用方法同上,区别在于生成的是getter方法。
    @ToString :注解在类,添加toString方法。
    @EqualsAndHashCode: 注解在类,生成hashCode和equals方法。
    @NoArgsConstructor: 注解在类,生成无参的构造方法。
    @RequiredArgsConstructor: 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
    @AllArgsConstructor: 注解在类,生成包含类中所有字段的构造方法。
    @Data: 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
    @Slf4j: 注解在类,生成log变量,严格意义来说是常量。

10、多对一与一对多

联表查询。

多个学生对应一个老师,老师的id对应学生的tid。

创建这两张表的sql语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

image-20200725100251765

  • 如果要查询所有的学生表,已经关联的所有老师:

    1
    select s.id s.name t.id t.name from student s,teacher t where s.tid = t.id;

例如如下的两张表:

image-20200725113252815

image-20200725113338525

  • student表的tid对应teacher表的id。那么我想实现如下的查询结果该如何实现。

image-20200725113439096

10.1、多对一处理:

10.1.1、方式1,类似于子查询:

  • 实体类:

    `````
    package com.aaron.pojo;

    public class Student {

    private int id;
    private String name;
    //学生需要关联一个老师
    private Teacher teacher;
    
    public Student() {
    }
    
    public Student(int id, String name, Teacher teacher) {
        this.id = id;
        this.name = name;
        this.teacher = teacher;
    }
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Teacher getTeacher() {
        return teacher;
    }
    
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", teacher=" + teacher +
                '}';
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40

    ```java
    package com.aaron.pojo;

    public class Teacher {
    private int id;
    private String name;

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

    public Teacher() {
    }

    public int getId() {
    return id;
    }

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

    public String getName() {
    return name;
    }

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

    @Override
    public String toString() {
    return "Teacher{" +
    "id=" + id +
    ", name='" + name + '\'' +
    '}';
    }
    }
  • StudentMapper.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.aaron.dao.StudentMapper">
    <select id="getStudentList" resultMap="StudentTeacher">
    select * from student;
    </select>
    <select id="getTeacher" resultType="com.aaron.pojo.Teacher">
    select * from teacher where id = #{tid}
    </select>

    <resultMap id="StudentTeacher" type="com.aaron.pojo.Student">
    <result property="id" column="id"></result>
    <result property="name" column="name"/>
    <!--对于复杂的属性:对象:association。集合:collection。-->
    <association property="teacher" column="tid" javaType="com.aaron.pojo.Teacher" select="getTeacher"/>
    </resultMap>
    </mapper>
  • 以上的步骤很像子查询处理。

    image-20200725121132359

10.1.2、方式2,按照结果嵌套查询:

  • 在StudentMapper.xml文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!--按照结果嵌套查询-->
    <select id="getStudentList2" resultMap="StudentTeacher2">
    select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid = t.id;
    </select>
    <resultMap id="StudentTeacher2" type="com.aaron.pojo.Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="com.aaron.pojo.Teacher">
    <result property="name" column="tname"/>
    </association>
    </resultMap>

image-20200725120745107

10.2、一对多处理:

  • sql查询语句:

    1
    select t.id,t.name tname,s.id sid,s.name sname from student s,teacher t where s.tid = t.id;
  • 实体类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    package com.aaron.pojo;

    public class Student {
    private int id;
    private String name;
    private int tid;

    public Student(int id, String name, int tid) {
    this.id = id;
    this.name = name;
    this.tid = tid;
    }

    public Student() {
    }

    public int getId() {
    return id;
    }

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

    public String getName() {
    return name;
    }

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

    public int getTid() {
    return tid;
    }

    public void setTid(int tid) {
    this.tid = tid;
    }

    @Override
    public String toString() {
    return "Student{" +
    "id=" + id +
    ", name='" + name + '\'' +
    ", tid=" + tid +
    '}';
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    package com.aaron.pojo;

    import java.util.List;

    public class Teacher {
    private int id;
    private String name;
    //一个老师拥有多个学生
    Student students;

    public Teacher() {
    }

    public Teacher(int id, String name, Student students) {
    this.id = id;
    this.name = name;
    this.students = students;
    }

    public int getId() {
    return id;
    }

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

    public String getName() {
    return name;
    }

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

    public Student getStudents() {
    return students;
    }

    public void setStudents(Student students) {
    this.students = students;
    }

    @Override
    public String toString() {
    return "Teacher{" +
    "id=" + id +
    ", name='" + name + '\'' +
    ", students=" + students +
    '}';
    }
    }
  • TeacherMapper.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--结果嵌套查询-->
    <select id="getTeacher" resultMap="TeacherStudent">
    select t.id,t.name,s.id,s.name,s.tid from student s,teacher t
    where s.tid = t.id and t.id = #{id};
    </select>
    <resultMap id="TeacherStudent" type="com.aaron.pojo.Teacher">
    <result property="id" column="t.id"/>
    <result property="name" column="t.name"/>
    <collection property="students" ofType="com.aaron.pojo.Student">
    <result property="id" column="s.id"/>
    <result property="name" column="s.name"/>
    <result property="tid" column="s.tid"/>
    </collection>
    </resultMap>

10.3、小结:

  1. 关联-associate【多对一】
  2. 集合-collation【一对多】
  3. javaType和ofType

11、动态SQL

什么是动态SQL:动态Sql就是指根据不同的条件生成不同的SQL语句。

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

11.1、if语句:

  • BlogMapper.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    <mapper namespace="com.aaron.dao.BlogMapper">
    <select id="getBlogList" parameterType="map" resultType="com.aaron.pojo.Blog">
    select * from mybatistest.blog where 1 = 1
    <if test="title != null">and title = #{title}</if>
    <if test="author != null">and author = #{author}</if>
    </select>
    </mapper>
  • test.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.aaron.dao;

    import com.aaron.pojo.Blog;
    import com.aaron.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;

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

    public class BlogMapperTest {
    public static void main(String[] args) {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title","红楼梦");
    map.put("author","曹雪芹");
    List<Blog> blogList = blogMapper.getBlogList(map);
    for (Blog blog : blogList) {
    System.out.println(blog);
    }
    sqlSession.close();
    }
    }

11.2、常用标签:

  • choose、when、otherwise:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <select id="findActiveBlogLike"
    resultType="Blog">
    SELECT * FROM BLOG WHERE state = ‘ACTIVE’
    <choose>
    <when test="title != null">
    AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
    AND author_name like #{author.name}
    </when>
    <otherwise>
    AND featured = 1
    </otherwise>
    </choose>
    </select>
  • trim、where、set:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <select id="findActiveBlogLike"
    resultType="Blog">
    SELECT * FROM BLOG
    <where>
    <if test="state != null">
    state = #{state}
    </if>
    <if test="title != null">
    AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
    AND author_name like #{author.name}
    </if>
    </where>
    </select>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <update id="updateAuthorIfNecessary">
    update Author
    <set>
    <if test="username != null">username=#{username},</if>
    <if test="password != null">password=#{password},</if>
    <if test="email != null">email=#{email},</if>
    <if test="bio != null">bio=#{bio}</if>
    </set>
    where id=#{id}
    </update>
    1
    2
    3
    4
    5
    6
    7
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
    ...
    </trim>

    <trim prefix="SET" suffixOverrides=",">
    ...
    </trim>

11.3、sql片段:

我们会将一些公用的片段抽取出来,实现复用。

1
2
3
4
5
<sql id="">
<if>.....
</sql>

底下引用时,只需要使用<include refid="">标签就可以导入该片段。

11.4、foreach:

  • 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
1
2
3
4
5
6
7
8
9
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>

12、缓存

查询:连接数据库耗资源。一次查询的结果,给他暂存在一个可以直接取到的地方——》内存,缓存。我们再次查到相同数据的时候,直接走缓存,就不用走数据库了。

参考文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

image-20200726094620034

image-20200726094637092

12.1、一级缓存:

12.2、二级缓存:

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

image-20200726103118359

1
<cache/>

12.3、自定义缓存:

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

介绍链接:https://www.jianshu.com/p/154c82073b07

12.4、redis做缓存:

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信