MyBatis学习笔记(系统学习)

文章目录

    • 一、简介
      • 1.MyBatis是什么
      • 2.持久层
      • 3.ORM
      • 4.回顾JDBC
    • 二、正式使用MyBatis的准备工作
      • 1. 需要在项目中添加JAR包
      • 2. 相关的配置文件的准备工作
    • 三、第一个MyBatis程序
      • 1. 数据库的设计
      • 2. 创建主配置文件
      • 3.创建映射文件
      • 4.MyBatis中数据库日志:log4j
      • 5.如何在IDEA中快速的使用数据库中的字段等信息来确定SQL语句
    • 四、基于接口的MyBatis映射文件
    • 五、MyBatis工具类
    • 六、MyBatis主配置文件的扩展:配置别名,引用属性文件
    • 七、MyBatis对数据库表的基本操作
      • 1.在插入操作中返回主键值
      • 2.更新操作
      • 3.删除操作
      • 4.查询操作
      • 5.手动映射
      • 6.多参数查询
      • 7.模糊查询
    • 八、动态SQL
      • 1.动态SQL之if标签
      • 2.动态SQL之choose标签
      • 3.动态SQL之where标签
      • 4.动态SQL之set标签
      • 5.动态SQL之trim标签
      • 6.动态SQL之foreach标签
    • 九、多表关系之间的映射
      • 1.多表关系映射
      • 2.查询操作之:多对一操作
      • 3.查询操作之:一对多操作
    • 十一、代码生成器
      • 1.简介
      • 2.用法
        • 2.1 添加jar包
        • 2.2 配置插件的配置文件
        • 2.3 自动生成代码
      • 3.分页插件

一、简介

1.MyBatis是什么

Mybatis的前身是Batis,他是一个持久层框架,或称为:ORM框架。

  • 总结:MyBatis就是用来访问数据库的!
  • 本质上对前面所学JDBC进行封装!

注意:所谓的框架就是别人已经写好的,对一些技术进行封装,比如:java框架一般会封装成为JAR;像其他的如JS,CSS等。而用了ORM框架,就不需要像之前操作JDBC数据库那样,一步一步进行编写,通过MyBatis可以快速的操作数据库!

2.持久层

DAO:Data Access Object 数据访问对象

用来对数据进行持久化操作,如将数据存入数据库、硬盘等,可以持久保存

3.ORM

Object Relation Mapping 对象关系映射,指的是java程序和数据库之间的映射关系

  • 类---->表
  • 对象—>一条数据或一条记录
  • 属性---->列

4.回顾JDBC

JDBC操作数据库的步骤:

  • Class.forName(DriverName)
  • DriverManager.getConnection(URL)
  • conn.prepareStatement()
  • ResultSet rs = ps.executeQuer()
  • while(rs.next()){} 通过这一步进行循环!
  • rs.close
  • statement.close
  • conneciton.close

在这数据库操作的一系列流程中,有些代码是不变的,有些代码是可变的

  • 数据库操作的可变部分:连接信息

DriverClassName,URL,user,password(也称这)

  • SQL语句
  • RM映射

二、正式使用MyBatis的准备工作

1. 需要在项目中添加JAR包

  • mymybatis-3.2.8.jar;版本话,3.0后面的版本都可以用!
  • mysql-connector-java;数据库驱动
  • log4j;日志包(可选)加入了这个包,可以看到日志的信息

这里的三个Jar包可以通过IDEA直接加载,也可以通过Maven或Gradle来进行加载

2. 相关的配置文件的准备工作

mybatis配置文件使用的是.xml文件,可以分为两大类:

  • config文件

主配置文件 ,在一个mybatis工程中有且只有一个,他是用来配置与整个工程配置相关的信息,如环境配置、插件配置、注册mapper文件等!

  • mapper文件

映射配置文件,在一个mybatis工程中可以有多个mapper文件,每一个mapper文件相当于原来的Dao的实现类。用来配置Dao功能的相关的SQL操作,如SQL语然啦,CRUD ,字段映射等!

注意:创建MyBatis的主配置文件时,如果一段代码需要重复利用的话,可以用模板来创建!

三、第一个MyBatis程序

1. 数据库的设计

在这里对一个数据库进行设计;

2. 创建主配置文件

核心配置文件,该文件一般位于src目录下,一般命名为:mybatis-config.xml(这是习惯问题,其他文件名也可以

  • mybatis中的xml约束条件:

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  
configuration>
  • mybatis-config.xml核心配置文件实例

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
       
           <environments default="hello">
               
               <environment id="hello">
                   
                   <transactionManager type="jdbc">transactionManager>
                   
                   <dataSource type="POOLED">
                       <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                       <property name="url" value="jdbc:mysql://localhost:3306/newdb?useSSL=false&serverTimezone=UTC"/>
                       <property name="username" value="root"/>
                       <property name="password" value="123456"/>
                   dataSource>
               environment>
           environments>
configuration>
  • SqlSession(持久化管理器),他是Mybatis的核心,他的创建方法是由工厂来创建的,即:SqlSessionFactoryBuilder,具体代码示例如下:
@Bean
public Connection connection(){
    // TODO: 2021/7/26 创建一个工厂
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    InputStream resourceAsStream = SqlSessionFactoryBuilder.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory build = builder.build(resourceAsStream);
    // TODO: 2021/7/26 创建了持久化管理器 ,所谓工厂模式,是将配置信息放入工厂,最终将创建一个持久化管理器
    SqlSession sqlSession = build.openSession();
    Connection connection = sqlSession.getConnection();
    return connection;
}

3.创建映射文件

在数据库中有一个表,那么根据ORM,那么在JAVA中就会有一个对应的类,因此,在创建映射文件的时候,首先得在Java中创建一个类;

  • 创建对应数据库表的对类

用来配置DAO的SQL语句,每个数据库表和对应的类之间都有一个映射文件(xml文件)

  • 创建xml映射文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="abc">
    
    <insert id="insertUser" parameterType="com.dream.seeker.entity.impl.GradleUser">
        insert into customer(name,salary) values (#{name},#{salary})
    insert>
mapper>

我们自定义一个映射文件,映射文件名可以自定义,那么如何告诉应用程序我们定义的映射文件呢?

  • 注册映射文件

Mybatis中的主配置文件m中有一个和environments平行的标签mapper。示例如下:

<mappers>
    
    <mapper resource="mapper/mybatis-mapper.xml"/>
mappers>
  • 测试映射文件

映射文件是和主配置文件一体的文件,自定义好的映射文件(Mapper)需要在主配置文件中进行注册,映射文件有SQL语句,每个SQL语句都有类似于方法名一样的标识,我们在MyBatis中也可以称之为方法名;他还存在方法参数,该参数是Java中的一个数据对象或者普通的数据,这些对象中的属性值和普通数据就是要传入到数据库中的内容。

@Test
public void insertDate() {
    gradleUser.setName("hellojava");
    gradleUser.setSalary(3000);
    // TODO: 2021/7/27:方式一:纯配置文件,没有接口,直接读取Mapper文件中的SQL语句!
    sqlSession.insert("abc.insertUser",gradleUser);
    // TODO: 2021/7/27 由于在主配置文件中,自动事务提交管理是关闭的,因此,需要手动对事务进行提交 
    sqlSession.commit();
}

4.MyBatis中数据库日志:log4j

在MyBatis中,如果需要对数据库的操作进行日志输出,则需要加载数据库日志输出依赖,并配置属性文件,具体代码如下:

  • 添加log4j依赖文件
<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>
  • 配置log4j属性文件

log4j属性文件必须在类路径src下,且文件名必须命名为:log4j.properties,属性文件的具体内容可以设置如下

log4j.rootLogger=INFO,console,dailyFile
# TODO 发布到阿里云记得添加,另外控制台不输出(只输出warn或者error信息)

# log4j.logger.org.mybatis = INFO
log4j.logger.com.imooc.mapper=INFO

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.encoding=UTF-8
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%l] - [%p] %m%n

# 定期滚动日志文件,每天都会生成日志
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.encoding=UTF-8
log4j.appender.dailyFile.Threshold=INFO
# TODO 本地日志地址,正式环境请务必切换为阿里云地址
log4j.appender.dailyFile.File=C:/logs/maven-ssm-alipay/log.log4j
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%l] - [%p] %m%n
  • 详细log4j配置文件案例:
log4j.rootLogger=INFO,consoleAppender,logfile,MAIL
log4j.addivity.org.apache=true
#ConsoleAppender,控制台输出
#FileAppender,文件日志输出
#SMTPAppender,发邮件输出日志
#SocketAppender,Socket 日志
#NTEventLogAppender,Window NT 日志
#SyslogAppender,
#JMSAppender,
#AsyncAppender,
#NullAppender
#文件输出:RollingFileAppender
#log4j.rootLogger = INFO,logfile
log4j.appender.logfile = org.apache.log4j.RollingFileAppender
log4j.appender.logfile.Threshold = INFO
# 输出以上的 INFO 信息
log4j.appender.logfile.File = INFO_log.html
#保存 log 文件路径
Log4j 从入门到详解
10
log4j.appender.logfile.Append = true
# 默认为 true,添加到末尾,false 在每次启动时进行覆盖
log4j.appender.logfile.MaxFileSize = 1MB
# 一个 log 文件的大小,超过这个大小就又会生成 1 个日志 # KB ,MB,GB
log4j.appender.logfile.MaxBackupIndex = 3
# 最多保存 3 个文件备份
log4j.appender.logfile.layout = org.apache.log4j.HTMLLayout
# 输出文件的格式
log4j.appender.logfile.layout.LocationInfo = true
#是否显示类名和行数
log4j.appender.logfile.layout.Title
=title:\u63d0\u9192\u60a8\uff1a\u7cfb\u7edf\u53d1\u751f\u4e86\u4e25\u91cd\u9519\u8b
ef
#html 页面的 < title >
############################## SampleLayout ####################################
# log4j.appender.logfile.layout = org.apache.log4j.SampleLayout
############################## PatternLayout ###################################
# log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
# log4j.appender.logfile.layout.ConversionPattern =% d % p [ % c] - % m % n % d
############################## XMLLayout #######################################
# log4j.appender.logfile.layout = org.apache.log4j.XMLLayout
# log4j.appender.logfile.layout.LocationInfo = true #是否显示类名和行数
############################## TTCCLayout ######################################
# log4j.appender.logfile.layout = org.apache.log4j.TTCCLayout
# log4j.appender.logfile.layout.DateFormat = ISO8601
#NULL, RELATIVE, ABSOLUTE, DATE or ISO8601.
# log4j.appender.logfile.layout.TimeZoneID = GMT - 8 : 00
# log4j.appender.logfile.layout.CategoryPrefixing = false ##默认为 true 打印类别名
# log4j.appender.logfile.layout.ContextPrinting = false ##默认为 true 打印上下文信息
# log4j.appender.logfile.layout.ThreadPrinting = false ##默认为 true 打印线程名
# 打印信息如下:
#2007 - 09 - 13 14 : 45 : 39 , 765 [http - 8080 - 1 ] ERROR com.poxool.test.test -
error 成功关闭链接
###############################################################################
#每天文件的输出:DailyRollingFileAppender
#log4j.rootLogger = INFO,errorlogfile
log4j.appender.errorlogfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.errorlogfile.Threshold = ERROR
log4j.appender.errorlogfile.File = ../logs/ERROR_log
log4j.appender.errorlogfile.Append = true
#默认为 true,添加到末尾,false 在每次启动时进行覆盖
log4j.appender.errorlogfile.ImmediateFlush = true
#直接输出,不进行缓存
# ' . ' yyyy - MM: 每个月更新一个 log 日志
# ' . ' yyyy - ww: 每个星期更新一个 log 日志
# ' . ' yyyy - MM - dd: 每天更新一个 log 日志
# ' . ' yyyy - MM - dd - a: 每天的午夜和正午更新一个 log 日志
# ' . ' yyyy - MM - dd - HH: 每小时更新一个 log 日志
# ' . ' yyyy - MM - dd - HH - mm: 每分钟更新一个 log 日志
Log4j 从入门到详解
11
log4j.appender.errorlogfile.DatePattern = ' . ' yyyy - MM - dd ' .log '
#文件名称的格式
log4j.appender.errorlogfile.layout = org.apache.log4j.PatternLayout
log4j.appender.errorlogfile.layout.ConversionPattern =%d %p [ %c] - %m %n %d
#控制台输出:
#log4j.rootLogger = INFO,consoleAppender
log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.Threshold = ERROR
log4j.appender.consoleAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern =%d %-5p %m %n
log4j.appender.consoleAppender.ImmediateFlush = true
# 直接输出,不进行缓存
log4j.appender.consoleAppender.Target = System.err
# 默认是 System.out 方式输出
#发送邮件:SMTPAppender
#log4j.rootLogger = INFO,MAIL
log4j.appender.MAIL = org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold = INFO
log4j.appender.MAIL.BufferSize = 10
log4j.appender.MAIL.From = [email protected]
log4j.appender.MAIL.SMTPHost = smtp.gmail.com
log4j.appender.MAIL.Subject = Log4J Message
log4j.appender.MAIL.To = [email protected]
log4j.appender.MAIL.layout = org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern =%d - %c -%-4r [%t] %-5p %c %x - %m %n
#数据库:JDBCAppender
log4j.appender.DATABASE = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL = jdbc:oracle:thin:@ 210.51 . 173.94 : 1521 :YDB
log4j.appender.DATABASE.driver = oracle.jdbc.driver.OracleDriver
log4j.appender.DATABASE.user = ydbuser
log4j.appender.DATABASE.password = ydbuser
log4j.appender.DATABASE.sql = INSERT INTO A1 (TITLE3) VALUES ( ' %d - %c %-5p %c %x - %m%n
' )
log4j.appender.DATABASE.layout = org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern =% d - % c -%- 4r [ % t] %- 5p % c %
x - % m % n
#数据库的链接会有问题,可以重写 org.apache.log4j.jdbc.JDBCAppender 的 getConnection() 使用数
据库链接池去得链接,可以避免 insert 一条就链接一次数据库

5.如何在IDEA中快速的使用数据库中的字段等信息来确定SQL语句

通过IDEA可以连接MySQL数据库,连接数据库后,在编写mapper文件的时候可以有提示信息,可以防止错误的发生。在IDEA连接数据库时,一定要注意设置serverTimezone=UTC,才能正确的连接

  • 连接数据库后,一般情况下也不会有提示信息,此时,需要对IDEA进行设置

File->Setting->Languages&Frameworks->SQL Dialects 将全局和项目的SQL Dialects都设置为:MySQL

四、基于接口的MyBatis映射文件

基于接口的映射文件,他和纯配置文件的主要区别在于:

  • 纯配置文件是通过持久性管理器sqlSession来调用映射文件中的SQL语句对数据库进行操作;
  • 而 接口 + 配置文件 的方式是通过接口生成的实现类(代理类)来执行接口中现有的方法来执行SQL语句,接口中的方法名 和 映射配置文件中的方法名必须一致,因此,通过调用接口实现类(由字节码操作工具类动态生成的代理对象)中的方法来驱动映射配置文件中的方法,从而执行SQL语句,达到操作数据库的目的!

具体案例代码:

  • 自定义一个操作数据库的接口
package com.dream.seeker.dao;

import com.dream.seeker.entity.impl.GradleUser;

public interface InsertUser {
    public void insertUser(GradleUser user);
}
  • 配置MyBatis映射配置文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dream.seeker.dao.InsertUser">
    
    <insert id="insertUser" parameterType="com.dream.seeker.entity.impl.GradleUser">
        insert into
            gradle(name, salary) values (#{name},#{salary})
    insert>
mapper>
  • 通过测试类来执行SQL语句
@Test
public void test97() {
    gradleUser.setName("hello");
    gradleUser.setSalary(200);
    // TODO: 2021/7/27 通过getMapper()方法,在方法中传入接口的结构信息,可以动态创建一个代理类对象 
    InsertUser mapper = sqlSession.getMapper(InsertUser.class);
    // TODO: 2021/7/27 通过动态生成的代理类对象调用其中方法来驱动映射配置文件中的SQL语句,或者可以说:SQL语句已经动态生成到接口实现类中的方法当中
    mapper.insertUser(gradleUser);
    // TODO: 2021/7/27 由于在MyBatis主配置文件中,事务管理属性JDBC,因此,需要手动提交事务
    sqlSession.commit();
}

知识点:通过接口 + 配置文件 的方式来操作数据库,他基本原理是:通过接口的结构信息 + 配置文件中与接口方法名相同的SQL语句,动态生成(由字节码操作工具)一个接口的实现类及实现类对象,通过这个实现类对象(代理类对象)调用对象中的方法来执行SQL语句,从而操作数据库。其主要优点是:接口动态生成的实例对象每一个方法都对应映射文件中的一个SQL语句!

五、MyBatis工具类

  • 下面的代码,如果每次都要写,那就比较麻烦。
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    InputStream resourceAsStream = SqlSessionFactoryBuilder.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory build = builder.build(resourceAsStream);
    // TODO: 2021/7/26 创建了持久化管理器 ,所谓工厂模式,是将配置信息放入工厂,最终将创建一个持久化管理器
    SqlSession sqlSession = build.openSession();

因此,在这种情况下,我们可以创建一个工具类,返回一个持久化管理器SqlSession ,同时,需要注意的是:在工具类中,SqlSession对象必须是单例唯一的。具体示例代码如下:

public class GradleMyBatisUtils {

    private static SqlSessionFactory factory;
    // TODO: 2021/7/28 可以把ThreadLocal<>看成是一个容器,这个容器有判断hash值的方法,确定在里面的实例是否是唯一(即单例)
    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();

    static {
        try {
            factory = new SqlSessionFactoryBuilder().build(
                GradleMyBatisUtils.class.getClassLoader().getResourceAsStream("classpath:mybatis-config.xml")
            );
        } catch (Exception e) {
            throw new ExceptionInInitializerError("MyBatis初始化失败" + e.getMessage());
        }
    }

    // TODO: 2021/7/28 获取一个持久化管理器,管理器里包数据库连接池,事务和数据库连接的相关信息,具体内容和配置文件中有关
    public static SqlSession getSession(){
        // TODO: 2021/7/28 从容器中获得对象, 由于是单例的,所以,会依据类型进行匹配
        SqlSession sqlSession = local.get();
        if (sqlSession == null) {
            sqlSession = factory.openSession();
            local.set(sqlSession);
        }
        return sqlSession;
    }

    // TODO: 2021/7/28 关闭持久化管理对象,关闭此对象,会同时关闭数据库连接池中相关对象,如connection,statement等! 
    public static void close(){
        SqlSession sqlSession = local.get();
        if (sqlSession!=null) {
            sqlSession.close();
            local.remove();
        }
    }
}

新增知识点:在工具类中,我们可以用ThreadLocal类实例来管理工具类中对象是否为单例,ThreadLocal实例具有存储和管理工具类中指定对象类型的功能,可以用来判断工具类中主对象是否为空,如果不为空的话,可以通过get()方法直接获得相应的对象。

  • 对MyBatis工具类进行测试
@Test
public void test110() {
    SqlSession sqlSession = null;
    try {
        // TODO: 2021/7/28 从工具类中获得持欠化管理器 
        sqlSession = MyBatisUtils.getSession();

        // TODO: 2021/7/28 下面几段代码是具体对数据库进行操作的代码  
        GradleUser gradleUser = new GradleUser();
        gradleUser.setName("hellojava");
        gradleUser.setSalary(5000);
        InsertUser mapper = sqlSession.getMapper(InsertUser.class);
        mapper.insertUser(gradleUser);

        // TODO: 2021/7/28 由于事务采取的方式是JDBC方式,他自动提交是关闭的,因此,需要手动关闭 
        sqlSession.commit();
    } catch (Exception e) {
        e.printStackTrace();
        // TODO: 2021/7/28 如果发生异常,事务没有执行完,地么需要回滚操作 
        sqlSession.rollback();
    } finally {
        MyBatisUtils.close();
    }
}

六、MyBatis主配置文件的扩展:配置别名,引用属性文件

  • typeAliases给自定义数据信息类设置别名

在主配置文件中,添加标签选项:typeAliases,可以为java类对象设置别名(这个JAVA类对象是存储数据库信息的Bean,使用此类对象设置数据,再将此类对象中的数据传入到数据库),这个java类对象是执行SQL方法中的参数,这个参数他位于MyBatis映射文件中。设置别名主要是在MyBatis主配置文件中,使用标签typeAliases,具体示例如下:

 
<typeAliases>
    
    
    
    <package name="com.dream.seeker.entity.impl"/>
typeAliases>

设置好别名后,那么就可以在MyBatis映射文件中使用别名了,下面的代码是基于接口 + 配置文件的方式定义的mapper(映射)文件,其中namesapce是接口名,id指的是接口的抽象方法名,而parameterType这个地方通过在主配置文件中定义的别名,可以简化许多代码。


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dream.seeker.dao.InsertUser">
    
    <insert id="insertUser" parameterType="GradleUser">
        insert into
        gradle(name, salary) values (#{name},#{salary})
    insert>
mapper>
  • 在属性文件中写数据库的连接信息:

在属性文件中写连接信息,首先得定义一个属性文件xxxx.properties,将相关的连接信息写入到里面,案例如下:

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/newdb?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=123456

在定义完属性文件后,需要在MyBatis的主配置文件中将自定义的属性文件添加到主配置文件中,在主配置文件中,用到了标签:properties,具体代码案例如下:

<properties resource="dbcp.properties"/>

在MyBatis主配置文件中定义好了属性文件后,则可以改写主配置文件中的连接信息,改写的内容采用 表 达 式 , 连 接 信 息 也 是 通 过 属 性 后 置 处 理 器 的 结 {}表达式,连接信息也是通过属性后置处理器的结 {}表达式进行转换,具体代码案例如下:

<dataSource type="POOLED">
    <property name="driver" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
dataSource>

七、MyBatis对数据库表的基本操作

1.在插入操作中返回主键值

基于接口 + 配置文件 的方式对数据库进行插入操作SQL时,一般情况下是不返回主键的,如果需要返回主键,那么需要在mapper文件中添加属性:userGeneratedKey。此属性的作用是保留进行插入SQL操作时的主键,此主键的值保存在哪个位置呢?答案是:保存到方法参数对象的属性中,然而,自定义的参数对象有许多属性,他又会保存到哪个属性当中呢,这时,在mapper文件中,又需要用到一个属性名为KeyProertyr的属性,此属性指的是自定义参数对象中哪个属性。具体代码案例流程如下:

  • 自定义数据Bean的结构信息
@Component(value = "gradleuser")
public class GradleUser {

    private int id;
    private String name;
    private long salary;

    ...
}
  • 在接口中添加新的方法
public interface InsertUser {
    public void insertUser(GradleUser user);
    public void insertGradle(GradleUser user);
}
  • 在映射文件(mapper)中 设置能返回主键的相关参数
<insert id="insertGradle" parameterType="GradleUser" useGeneratedKeys="true" keyProperty="id">
    insert into gradle(name, salary) VALUES (#{name},#{salary})
insert>
  • 通过测试方法来对
@Test
public void test130() {
    SqlSession sqlSession = null;
    try {
        sqlSession = MyBatisUtils.getSession();

        GradleUser gradleUser = new GradleUser();
        gradleUser.setName("thisisjava");
        gradleUser.setSalary(3500);

        InsertUser mapper = sqlSession.getMapper(InsertUser.class);
        mapper.insertGradle(gradleUser);
        System.out.println(gradleUser.getId());

        sqlSession.commit();
    } catch (Exception e) {
        e.printStackTrace();
        sqlSession.rollback();
    } finally {
        MyBatisUtils.close();
    }
}

2.更新操作

在这时统一学习的是基于接口+ 配置文件 的方式

  • 在接口中定义一个更新操作的方法
  • 在映射文件中增加更新操作的标签update

具体代码示例如下:

  • 在接口进定义更新方法
public interface BatisOne {
   void insertStudent(Student student);
   void updataStudent(Student student);
   void deleteStudent(int id);
}
  • 在映射文件中定义更新操作的标签,并配置相关信息
<update id="updataStudent" parameterType="Student">
    
    update student set name=#{name},age = ${age} where id=#{id}
update>
  • 测试
@Test
public void test46() {
    Student student = new Student(1, "hellojava", 30);
    batisOne.updataStudent(student);
}

3.删除操作

通过Mybatis以数据库表中的数据进行删除时,参数中可以不指定对象,可以直接指定数据库表中的一个数据类型做为参数,也就是我们常说的基本数据类型,如下面,Integer类型做为参数:

public interface BatisOne {
   void insertStudent(Student student);
   void updataStudent(Student student);
   void deleteStudent(int id);
}
<delete id="deleteStudent" parameterType="Integer">
    
    delete from student where id = #{id}  
delete>

基本数据类型做为参数时,在映身文件中的SQL语句中,#{XXX}中可以直接用接口方法 中定义的形参标识符来填充XXX点位符。

  • 测试:
@Test
public void test52() {
    batisOne.deleteStudent(1); //这个地方直接传入基本数据类型
}

4.查询操作

在mybatis映射文件中有一个标签为:select,可以对数据库中的数据进行查询操作

<--前提条件:查询结果的字段名必须和对象的属性名相同 -->
<select id="selectStudent" parameterType="Integer" resultType="Student">
    select id,name,age from student where id=#{id}
select>
  • 返回的是一个对象,会自动进行映射,当然,查询后的结果集字段名必须和对象中的属性名相相同

  • 对于返回值为一个集合时,这个集合是一个容纳Student对象的集合,那么在映射文件的参数也可以是Student对象,因为Mybatis帮我们封装了许多技术,可以逐条的将数据库表中的每条记录映射到Student对象中,再将对象放入集合中。

具体代码示例如下:

  • 在接口中定义方法,接口中的所有方法必须和映射文件中的SQL操作相对应
public interface BatisOne {
   void insertStudent(Student student);
   void updataStudent(Student student);
   void deleteStudent(int id);
   Student selectStudent(int id);
   List<Student> selectAll();
}
  • 在映射文件中创建与接口中方法相对应的SQL语句标签
<select id="selectStudent" parameterType="Integer" resultType="Student">
    select id,name,age from student where id=#{id}
select>
<select id="selectAll" resultType="Student">
    select <include refid="studentFiled">include> from student
select>
  • 补充知识点:如果一个数据库中的字段很多,每次在映射文件中写SQL语句时,就会比较繁琐,因此,MyBatis在映身文件中定义了SQL语句片断,定义好的片断可以在SQL语句中进行引用,具体代码示例如下:

<sql id="studentFiled">
    id,name,age
sql>

<select id="selectAll" resultType="Student">
    select <include refid="studentFiled">include> from student
select>

整体映射文件代码如下:包含了更新,删除、查询的所有语句


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="dream.dao.batis.BatisOne">

    
    <sql id="studentFiled">
        id,name,age
    sql>
    <insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
        insert into student(name, age) values (#{name},#{age})
    insert>
    <update id="updataStudent" parameterType="Student">
        update student set name=#{name},age = ${age} where id=#{id}
    update>
    <delete id="deleteStudent" parameterType="Integer">
        delete from student where id = #{id}
    delete>
    <select id="selectStudent" parameterType="Integer" resultType="Student">
        select id,name,age from student where id=#{id}
    select>
    
    <select id="selectAll" resultType="Student">
        select <include refid="studentFiled">include> from student
    select>

mapper>

5.手动映射

  • 自动映射:指的是查询结果集的字段名和自定义对象的属性名相同

  • 手动映射:在查询结果集和自定义对象属性名不相同

如何进行手动映射:

在学习手动映射之前,我们需要定义一个自定义对象,这个对象的属性和数据库表中的字段名不一样,如下:

public class NewStudent {

    private int user_id;
    private String user_name;
    private int user_age;
    ...
}
  • 第一种方式:使用别名,也就是将查询结果集的字段都设置成别名,别名的名字必须和自定义对象的属性名字相同。(这种方式一般不常使用)
<select id="selectNewStudent" parameterType="Integer" resultType="NewStudent">
    select id user_id, name user_name, age user_age
    from student
    where id = #{id}
select>
  • 第二种方式:使用resultMap:resultMap用于在映射文件中标签中,是用来定义结果的映射,作用是将数据库的字段与对象的属性进行对应的映射,在标签中使用resultMap时,需要在外部定义一个映射标签:
    
    <resultMap id="studentMapper" type="NewStudent">
        <id property="user_id" column="id"/>
        <result property="user_name" column="name"/>
        <result property="user_age" column="age"/>
    resultMap>

定义好resultMap,就可以在映射文件中的SQL语句中使用定义的resultMap了

<select id="selectTwoStudent" parameterType="Integer" resultMap="studentMapper">
    select id, name, age
    from student
    where id = #{id}
select>

6.多参数查询

基于接口和映射配置文件定义的Mybatis中,如果接口定义中的方法定义了两个参数,应该如何处理呢?

  • 重点:学习这点,可以认为把映射文件中的SQL语句都移到了接口的实现类中,这样,更容易理解 SQL语句对形参的调用。

  • 有多个参数,那么在SQL中可以就不写了,在映射文件的SQL不写参数还可以用于Map集合做为接口方法中的参数。

**第一种方式:**在接口中定义的参数,实际上有索引的,第一个参数为0,第二个参数为1。通过实验,这种情况一般用不了,可以在sql语句的点位符中直接引有形参名。

  • 定义接口中的方法和参数
// TODO: 2021/8/11 这里使用索引的方式,一般情况下,索引无效,可以直接使用参数名放在占位符中
ClassStudent selectStudent(String dname, int age);
  • 在映射文件中实现与接口方法对应的SQL语句

<select id="selectStudent" resultType="ClassStudent">
    select name,age,address from dbuser where name=#{dname} and age=#{age}
select>

**第二种方式:**使用@Param注解,他是标注在接口方法的参数前,注解中定义的名称,也是在映射文件的SQL语句点位符所要用到的名称。

  • 定义接口中的方法和参数
// TODO: 2021/8/11 这里使用注解的方式 ,由于是多参,所以在SQL映射文件中无需定义参数
ClassStudent selectTwoStudent(@Param(value = "helloname") String username, @Param(value = "helloage") int userage);
  • 在映射文件中实现与接口方法对应的SQL语句

<select id="selectTwoStudent" resultType="ClassStudent">
    select name,age,address from dbuser where name=#{helloname} and age=#{helloage}
select>

**第三种方式:**可以把多个参数变成一个参数,也就是参数封装成一个对象。一般常用的方法,传递进去的对象和返回的对象是同一个对象。如果要传递进去的参数在已知的定义的对象中没有相应的属性,那么可以再自定义一个封装类。

  • 定义接口中的方法和参数
// TODO: 2021/8/11 通过自定义对象,如果自定义对象中有能传递给语句的属性,而且返值也能放到这个对象中,那么参数和返回值可以是同一个类
ClassStudent selectClassStudent(ClassStudent student);
  • 在映射文件中实现与接口方法对应的SQL语句

<select id="selectClassStudent" parameterType="ClassStudent" resultType="ClassStudent">
    select name,age,address from dbuser where age=#{age}
select>

**第四种方式:**直接将参数封装成一个Map集合。在#{}占位符中,可以直接使用Map集合中Key的值。

  • 定义接口中的方法和参数
// TODO: 2021/8/11 在映射文件中的SQL语句中,无需定义参数,点位符使用Map中的Key值
ClassStudent selectMapStudent(Map map);
  • 在映射文件中实现与接口方法对应的SQL语句

<select id="selectMapStudent" resultType="ClassStudent">
    select name,age,address from dbuser where age=#{age}
select>

**总结分析:**在一般情况下,使用注解,和自下定义对象的方法比较居多,具体情况还得根据情况而定。

7.模糊查询

模糊查询主要有二种:一种是手动模糊查询;另一种是使用Bind进行查询

  • 手动模糊查询

使用手动模糊查询,模糊查询的匹配符是在外面进行定义的,映射文件里厕所SQL语句接收的参数仍是接口中定义的方法形参数标识名

  1. 在接口中定义方法,方法参数为要查询的内容
   List<Student> selectOut(String s);
  1. 在映入文件中定义用于模糊查询的SQL语句

<select id="selectOut" resultType="Student"> 
    select name,age from student where name like #{s}
select>
  1. 测试
@Test
public void test83() {
    String name = "a";
    List<Student> students = batisOne.selectOut("%"+name+ "%");
    for (Student student : students) {
        System.out.println(student);
    }
}
  • 使用Bind进行模糊查询

使用Bind进行模糊查询,也可以理解成为内置模糊查询,在方法外部不定义匹配标识符,而是在方法里面进行定义

  1. 在接口中定义方法,方法参数为要查询的内容
   List<Student> selectIn(String s);
  1. 在映入文件中定义用于模糊查询的SQL语句
<select id="selectIn" resultType="Student">
    select name,age from student
    <bind name="abc" value="'%'+_paramater+'%'"/>
    where name like #{abc}
select>
  1. 测试
@Test
public void test94() {
    String name = "c";
    List<Student> students = batisOne.selectIn(name);
    for (Student student : students) {
        System.out.println(student);
    }
}

八、动态SQL

根据条件的不同,动态的拼接SQL语句,称之为动态SQL。

动态SQL都是在在映射文件中利用相对应的标签进行定义的,其主要目的就是给指定要查询的语句进动态的拼接

1.动态SQL之if标签

SQL的if语句,其主用途是对传入的参数对象的某个属性进条件判断,如果条件为真,就可以执行或者拼接SQL语句。

  • 判断是在if标签中的test属性中进行的。

示例:对一个对象参数的属性进行条件判断,如果符合相应的条件,则进行SQL语句的拼接。

<select id="selectif" parameterType="Student" resultType="Student">
    select name, age
    from student
    where 1 = 1
    <if test="name!=null and name!=''">
        and name = #{name}
    if>
select>

注意点:判断条件中的属性都来源于方法中的参数,如果接口方法参数是一个自定义对象,那么就来源于这个自定义对象的属性。

2.动态SQL之choose标签

在映射文件中的SQL语句中,还有一个标签choose,用于条件的选择,其主要意思是:只会拼接一个SQL语句。

  • choose标签中,里面有一个子标签when,字标签配合test主要用于判断条件是否成立。
<select id="selectchoose" parameterType="Student" resultType="Student">
    select name, age
    from student
    where
    <choose>
        <when test="name != null and name !=''">
            name=#{name}
        when>
        <when test="age!=null and age!=0">
            age=#{age}
        when>
        <otherwise>
            1=1
        otherwise>
    choose>
select>

3.动态SQL之where标签

where标签:一般要结合if或choose一起使用,主要有两个作用:

  • 添加where关键字
  • 删除sql片段的第一个关键字,如and 或 or
  • 如果没有拼接任何sql片段,则不会添加where关键字
<select id="selectwhere" parameterType="Student" resultType="Student">
    select name,age from student
    <where>
        <if test="name != null and name != ''">
            and name=#{name}
        if>
    where>
select>

4.动态SQL之set标签

更新,修改的时候用set标签,set标签不能单独使用,一般也需要结合if和choose来使用。具体代码示例如下:

<update id="updateset" parameterType="Student">
    update student
    <set>
        <if test="name !=null and name !=''">
            name = #{name},
        if>
        <if test="age!=null and age!=0">
            age=#{age}
        if>
    set>
    <where>
        <if test="id!=null and id!=''">
            and id=#{id}
        if>
    where>
update>

5.动态SQL之trim标签

trim标签的作用,可以在语句的两边去除、增加相关的内容,其主要作用如下:

  • 可以在语句的开头、或者是末尾添加特定的前缀或后缀
  • 可以删除开头或末尾参数指定的内容
<select id="selecttrim" parameterType="Student" resultType="Student">
    select name,age from student
    <trim prefix="where" prefixOverrides="and|or">
        <if test="id != null">
            and id=#{id}
        if>
    trim>
select>

6.动态SQL之foreach标签

增强for循环,如在数据库表中,需要同时找出字段不同值的内容。foreach标签中有多个属性:

  • collection属性:要遍历的集合,主要意思是:所有的集合都会转换成一个Map,Map的key名是传入参数的类型。
  • item属性:迭代变量
  • open属性:遍历前添加的字符串
  • close属性:遍历后添加的字符串
  • spearator:元素的分隔符
  • index:遍历元素的索引

其主要代码示例如下:

  1. 在接口中定义方法
List<Student> selectforeach(List<Integer> list);
  1. 在映射文件中定义关于foreach标签的语句
<select id="selectforeach" resultType="Student">
    select name,age from student
    where id in
    <foreach collection="list" item="abc" open="(" close=")" separator=",">
        #{abc}
    foreach>
select>
  1. 测试
@Test
public void test153() {
    List<Integer> integers = Arrays.asList(3, 4);
    List<dream.entity.impl.Student> selectforeach = batisOne.selectforeach(integers);
    for (dream.entity.impl.Student student : selectforeach) {
        System.out.println(student);
    }
}

九、多表关系之间的映射

1.多表关系映射

多表映射关系核心思想

  • 每一个数据库表、数据库对象、接口、映射文件都是一一对应的关系
  • 在ORM中,一个数据库对象中的一个属性可以是另外一个数据库表对象
  • 当对象模型做为SQL语句的一个参数的时候,如果有一个属性是对象,那么在点位符#{}中可以用这个对象的属性。

具体代码录例如下:

映入文件中的SQL语句

<insert id="insertEmp" parameterType="Emp">
    insert into emp(empname, empage, deptid)
    VALUES (#{empname}, #{empage}, #{dept.deptid})
insert>

测试

@Test
public void test237() {
    Dept dept = new Dept();
    Dept dept1 = new Dept();
    dept.setDeptname("市场部");
    dept1.setDeptname("营销部");

    Emp emp1 = new Emp("admin", 20, dept);
    Emp emp2 = new Emp("javachello", 30, dept1);

    try {
        dreamDept.insertDept(dept);
        dreamDept.insertDept(dept1);

        dreamEmp.insertEmp(emp1);
        dreamEmp.insertEmp(emp2);

        MyBatisUtils.commit();
    } catch (Exception e) {
        MyBatisUtils.rollback();
        e.printStackTrace();
    } finally {
        MyBatisUtils.close();
    }
}

通过以上两段代码,基本上可以确定在ORM中,在多表中,一张表的对象模型,可以包含另外一张表的对象模型。

2.查询操作之:多对一操作

本节的学习,是 员工表emp为例,在java中,对应的有Emp员工对象,基于接口+ 映射文件,总共四个方面的内容(表、接品、映射配置文件、表对象)

在多对一关系中,一个员工对应有一个部门,一个部门在ORM中也是一个对象,所以,在emp对象中,部门dept就是作为员工对象国的一个属性。在本节中,主要解决的问题是:**如何通把查询出来的内容封装到一个对象中的对象属性。**在这里,主要有两种方式:

  • 第一种方式:直接使用手动映射

这种方式比较容易直观理解,其中心思想是:从数据库表获得的字段数据,根据手动映射关系直接传递到对象当中。

<resultMap id="empMapper" type="Emp">
    <id property="empid" column="empid"/>
    <result property="empname" column="empname"/>
    <result property="empage" column="empage"/>
    <association property="dept" javaType="Dept">
        <id property="deptid" column="deptId"/>
        <result property="deptname" column="deptName"/>
    association>
resultMap>
  • 第二种方式:嵌套使用手动映射

嵌套使用手动映射也有两种情况:

  1. 在同一个文件中定义另外一个对象的手动映射代码并使用。
  2. 在另外一个文件中定义对象的手动映射代码,并在这个文件中引用

也就是单独把对部门映像结分离出来,其主核心思想是,在配置手动映射的时候,如果一个属性是对象,那么可以针对这个对象定义一个手动配置文件(这个手动映射配置文件可以定义在同一个文件中,也可以定义在另外ORM中与数据库表相关联的映射配置文件中),在查询的映射文件中再通过association标签标签resultMap来使用再次定义的手动配置。

  • 在同一个文件中定义另外一个对象的手动映射代码并且引用
<resultMap id="deptmapperthis" type="Dept">
    <id property="deptid" column="deptId"/>
    <result property="deptname" column="deptName"/>
resultMap>

引用:

<resultMap id="empMapper2" type="Emp">
    <id property="empid" column="empid"/>
    <result property="empname" column="empname"/>
    <result property="empage" column="empage"/>
    <association property="dept" javaType="Dept" resultMap="deptmapperthis"/>
resultMap>
  • 在不同文件中定义另外一个对象的手动映射代码并且引用(此时,下面的代码是在dept映射文件中定义的手动映射代码)

    
    

引用:此时的引用是不同与上面的

<resultMap id="empMapper2" type="Emp">
    <id property="empid" column="empid"/>
    <result property="empname" column="empname"/>
    <result property="empage" column="empage"/>
    <association property="dept" javaType="Dept" 		resultMap="dream.dao.batis.DreamDept.deptmapper"/>
resultMap>

此地方需注意的是:查询语句必须包含能传递全手动映射代码所必须的字段值

第三种方式:通过查询过得的字段值传递给另外一张表进行查询

在association标签中,还有一个属性:select,他的主要作用是调用其他映射文件的查询语句,其中还有一个属性:column,这个属性的作用是在调用其他映射文件查询语句时,做为一个参数传递过去的。他做为一个参数传递给查询语句时,如果只有一个参数,查询语句接收参数时,可以任意命名。

  • 从emp表中,按字段正常查找字段值
<select id="selectAll" resultMap="empMapper3">
    select empid, empname, empage, deptid
    from emp
select>
  • 能过手动映射中的association标签中的select属性,执行另外一个映射文件的查询语句,查询语句需要传递参数,这时association标签中的column属性就是要传递的参数值,他是从表中获取得到数据。
<resultMap id="empMapper3" type="Emp">
    <id property="empid" column="empid"/>
    <result property="empname" column="empname"/>
    <result property="empage" column="empage"/>
    <association property="dept" javaType="Dept" select="dream.dao.batis.DreamDept.selectDept" column="deptid"/>
resultMap>

做为这三种方式,在实际项目中,我们用哪一种呢?

第三种方式是存在缺陷的,他会有多次查询。主要存在以下几种情况

  • 首先查询一次主表(emp )表,获得N条 dept_id记录
  • 对于每一个不同的dept_id,都会去对dept表进行一次查询,可能查询的资料为表的数据记录数
  • 所在,采取这种方式进行查询时,一般查询的次数为:emp表记录数 * dept表记录数

3.查询操作之:一对多操作

在一个对象中,定义另外一个对象集合,在java中可以这样理解,而在数据库表中,一对多可以理解为:通过Group BY 分组后的一个字段,在别的字段中包含有多条记录。

通过本节视频学习总结:一多对,在ORM模型中,一个对象中有一个集合属性,这个集合属性存储的是从另外一张表中获取的数据生成的对象。

一对多的操作也有三种方式,和多对一的方式是一样的

  • 直接定义手动映射文件
<resultMap id="deptnewmapper" type="Dept">
    <id property="deptid" column="deptid"/>
    <result property="deptname" column="deptname"/>
    <collection property="emps"  ofType="Emp">
        <id property="empid" column="empId"/>
        <result property="empname" column="empName"/>
        <result property="empage" column="empAge"/>
    collection>
resultMap>
  • 嵌套使用手动映射代码

嵌套使用手动映射代码,也有两种情况,一是直接使用同一文件中的映射代码,另一个是使用外部文件的映射代码



<sql id="newdeptfiled">
    d.deptid,
    d.deptname,
    e.empid 'empId',
    e.empname 'empName',
    e.empage 'empAge'
sql>

<resultMap id="deptnewmapper2" type="Dept">
    <id property="deptid" column="deptid"/>
    <result property="deptname" column="deptname"/>
    <collection property="emps" ofType="Emp" resultMap="otherdeptmapper"/>
resultMap>

<resultMap id="otherdeptmapper" type="Emp">
    <id property="empid" column="empId"/>
    <result property="empname" column="empName"/>
    <result property="empage" column="empAge"/>
resultMap>

<select id="selectAlldept" resultMap="deptnewmapper2">
    select <include refid="newdeptfiled"/>  from dept d left join emp e on d.deptid = e.deptid
select>
  • 使用单表查询,从单表中得到一个数据再查询另外一张表

其中心思想是:从一张表中得到字段数据,从其中的一个字段数据值做为另一个查询语句的参数,对第二张表进行查询,第二张表查询出来的字段值存储到ORM模型中的对象中,并将其对象传递给一对多对象的集合属性。

具体代码示例如下:

<select id="empselect" parameterType="Integer" resultType="Emp">
    select empid, empname, empage from emp where deptid = #{id}
select>

<resultMap id="one" type="Dept">
    <id property="deptid" column="deptid"/>
    <result property="deptname" column="deptname"/>
    <collection property="emps" ofType="Emp" select="empselect" column="deptid"/>
resultMap>

<select id="otherselectdept" resultMap="one">
    select deptid, deptname from dept
select>

注意:从字段获得数据值传递给第二个查询语句,这个查询语句可以在同一个文件中,也可以在另外一个文件中,只是引用的方式不同,引用外部文件的查询语句时,使用全类名路径文件名 + 查询语句的ID号。

十一、代码生成器

1.简介

mybatis-generator是一款Mybatis插件,能够自动生成Mybatis相关的代码,如:

  • dao接口
  • mapper映射文件
  • 实体类。他可以分为两种:
  1. 与数据库表相对应的java对象
  2. sql条件对象

当然,也在存缺点:

  • 生成的代码默认只支持单表操作
  • 多表查询需要自己编写
  • 对象之间的关系需要自己维护
  • 保存返回主键需要自己添加

2.用法

该插件并不是在开发过程中使用的,而是开发前做的准备工作

在开发之前通过该插件生成相关的代码,然后将生成的代码拷贝到工程中

2.1 添加jar包

使用该插件时,需要添加插件的jar包,但在开发的时候不需要添加,他主要有两个jar包

  • mybatis-generator-core
  • mysql-connector-java(数据库驱动)
  • mybatis-generator-maven-plugin(通过插件)
<plugin>
    <groupId>org.mybatis.generatorgroupId>
    <artifactId>mybatis-generator-maven-pluginartifactId>
    <version>1.4.0version>
    <configuration>
        <overwrite>trueoverwrite>
        <verbose>trueverbose>
    configuration>
plugin>

2.2 配置插件的配置文件

  • 名字为:generatorConfig.xml (说明一)

DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    
    
    
    
 
 
    
    
    
   
 
    
 
    <context id="Mysql" targetRuntime="MyBatis3Simple">
        
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
            
           
        plugin>
        
        <commentGenerator >
            
            
            
           
        commentGenerator>
 
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://192.168.9.107:3306/jack?useUnicode=true&characterEncoding=UTF8&useSSL=true"
                        userId="root"
                        password="root">
            
            <property name="useInformationSchema" value="true"/>
        jdbcConnection>
 
        
        <javaTypeResolver >
            
            <property name="forceBigDecimals" value="false" />
        javaTypeResolver>
 
        
        <javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}">
            
            
            
            
        javaModelGenerator>
 
        
        <sqlMapGenerator targetPackage="${targetXMLPackage}"  targetProject="${targetResourcesProject}">
            
           
        sqlMapGenerator>
 
        
        <javaClientGenerator type="XMLMAPPER" targetPackage="${targetMapperPackage}"  targetProject="${targetJavaProject}">
            
            
        javaClientGenerator>
 
        
        
        
           
            
            
            
           
       
        <table tableName="student"  domainObjectName="Student" />
 
    context>
generatorConfiguration>
  • generatorConfig.xml(说明二)

DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    
    <properties resource="dbcp-config.properties"/>
    <classPathEntry location="${jdbc.jar}"/>

    <context id="DB2Tables" targetRuntime="MyBatis3">

        
        <commentGenerator>
            <property name="suppressAllComments" value="false"/>
        commentGenerator>

        
        <jdbcConnection
                driverClass="${driverClassName}"
                connectionURL="${url}"
                userId="${username}"
                password="${password}">
        jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        javaTypeResolver>

        
        
        <javaModelGenerator targetPackage="com.dream.seeker" targetProject="./src/main/java">
            
            <property name="enableSubPackages" value="false"/>
            
            <property name="constructorBased" value="true"/>
            
            <property name="trimStrings" value="true"/>
            
            <property name="immutable" value="false"/>
        javaModelGenerator>

        
        <sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
            <property name="enableSubPackages" value="false"/>
        sqlMapGenerator>

        
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.*.dao" targetProject="./src/main/java">
            
            <property name="enableSubPackages" value="false"/>
        javaClientGenerator>


        <table tableName="admin" domainObjectName="Admin" enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
            <property name="rootInterface" value="com.*.dao.AdminExtMapper"/>
        table>

    context>
generatorConfiguration>
  • generatorConfig.xml(说明三)

DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    
    <properties resource="dbcp-config.properties"/>
    
    <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />

    
    <context id="mysql" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple" >

        
        <property name="autoDelimitKeywords" value="false"/>
        
        <property name="javaFileEncoding" value="UTF-8"/>
        
        <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
        
        <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>

        
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql:///pss" userId="root" password="admin">
            
        jdbcConnection>

        
        <javaTypeResolver type="org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl">
            
            <property name="forceBigDecimals" value="false"/>
        javaTypeResolver>


        
        <javaModelGenerator targetPackage="com._520it.mybatis.domain" targetProject="src/main/java">
            
            <property name="constructorBased" value="false"/>

            
            <property name="enableSubPackages" value="true"/>

            
            <property name="immutable" value="false"/>

            
            <property name="rootClass" value="com._520it.mybatis.domain.BaseDomain"/>

            
            <property name="trimStrings" value="true"/>
        javaModelGenerator>


        
        <sqlMapGenerator targetPackage="com._520it.mybatis.mapper" targetProject="src/main/resources">
            
            <property name="enableSubPackages" value="true"/>
        sqlMapGenerator>


        
        <javaClientGenerator targetPackage="com._520it.mybatis.mapper" type="ANNOTATEDMAPPER" targetProject="src/main/java">
            
            <property name="enableSubPackages" value="true"/>

            
        javaClientGenerator>

        
        <table tableName="userinfo" >

            
            <property name="constructorBased" value="false"/>

            
            <property name="ignoreQualifiersAtRuntime" value="false"/>

            
            <property name="immutable" value="false"/>

            
            <property name="modelOnly" value="false"/>

            

            

            

            

            

            
            <property name="selectAllOrderByClause" value="age desc,username asc"/>

            
            <property name="useActualColumnNames" value="false"/>


            

            


            
            <columnOverride column="username">
                
                <property name="property" value="userName"/>

                

                

                

                
            columnOverride>

            
        table>

    context>

generatorConfiguration>

2.3 自动生成代码

  • windows :执行execute.bat
  • Linux:执行execute.sh

将生成的代码直接拷贝到工程当中

2.4 对于xxxExample对象的理解

xxxExample是用于为接口 + 映射文件所形成的操作对象提供查询、增加、修改条件的,这一系列的操作都只针对单表操作,能过类对象进行相关的设置,极大简化的查询条件。

具体代码示例:希望能举一反三

@Test
public void test375() {

    StudentExample studentExample = new StudentExample();
    studentExample.or().andNameEqualTo("showme")
        .andAgeEqualTo(34);
    List<dream.dao.entity.Student> students = studentMapper.selectByExample(studentExample);
    for (dream.dao.entity.Student student : students) {
        System.out.println(student);
    }
}

@Test
public void test388() {
    StudentExample studentExample = new StudentExample();
    studentExample.or().andIdBetween(1,2);
    List<dream.dao.entity.Student> students = studentMapper.selectByExample(studentExample);
    for (dream.dao.entity.Student student : students) {
        System.out.println(student);
    }

}

3.分页插件

在项目开发的过程中,需要对项目过行分页显示,在mybatis中,有一个分页插件PageHelper,他是一款Mybatisr的分页插件。

  • 添加jar包
<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.2.1version>
dependency>

<dependency>
    <groupId>com.github.jsqlparsergroupId>
    <artifactId>jsqlparserartifactId>
    <version>4.0version>
dependency>
  • 在主配置文件mybatis-config.xml中配置分页属性,具体代码如下:

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        
        
        <property name="reasonable" value="true"/>
    plugin>
plugins>
  • 在代码中使用
@RequestMapping("/emps")
public String list(@RequestParam(required = false,defaultValue = "1",value = "pn")Integer pn,Map<String,Object> map){

    //引入分页查询,使用PageHelper分页功能
    //在查询之前传入当前页,然后多少记录
    PageHelper.startPage(pn,5);
    //startPage后紧跟的这个查询就是分页查询
    List<Employee> emps = employeeService.getAll();
    //使用PageInfo包装查询结果,只需要将pageInfo交给页面就可以
    PageInfo pageInfo = new PageInfo<>(emps,5);
    //pageINfo封装了分页的详细信息,也可以指定连续显示的页数

    map.put("pageInfo",pageInfo);
    return "list";
}
  • PageInfo类说明
public class PageInfo<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    //当前页
    private int pageNum;
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;
 
    //由于startRow和endRow不常用,这里说个具体的用法
    //可以在页面中"显示startRow到endRow 共size条数据"
 
    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总记录数
    private long total;
    //总页数
    private int pages;
    //结果集
    private List<T> list;
 
    //前一页
    private int prePage;
    //下一页
    private int nextPage;
 
    //是否为第一页
    private boolean isFirstPage = false;
    //是否为最后一页
    private boolean isLastPage = false;
    //是否有前一页
    private boolean hasPreviousPage = false;
    //是否有下一页
    private boolean hasNextPage = false;
    //导航页码数
    private int navigatePages;
    //所有导航页号
    private int[] navigatepageNums;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;
 
    public PageInfo() {
    }
 
    /**
     * 包装Page对象
     *
     * @param list
     */
    public PageInfo(List<T> list) {
        this(list, 8);
    }
 
    /**
     * 包装Page对象
     *
     * @param list          page结果
     * @param navigatePages 页码数量
     */
    public PageInfo(List<T> list, int navigatePages) {
        if (list instanceof Page) {
            Page page = (Page) list;
            this.pageNum = page.getPageNum();
            this.pageSize = page.getPageSize();
 
            this.pages = page.getPages();
            this.list = page;
            this.size = page.size();
            this.total = page.getTotal();
            //由于结果是>startRow的,所以实际的需要+1
            if (this.size == 0) {
                this.startRow = 0;
                this.endRow = 0;
            } else {
                this.startRow = page.getStartRow() + 1;
                //计算实际的endRow(最后一页的时候特殊)
                this.endRow = this.startRow - 1 + this.size;
            }
        } else if (list instanceof Collection) {
            this.pageNum = 1;
            this.pageSize = list.size();
 
            this.pages = this.pageSize > 0 ? 1 : 0;
            this.list = list;
            this.size = list.size();
            this.total = list.size();
            this.startRow = 0;
            this.endRow = list.size() > 0 ? list.size() - 1 : 0;
        }
        if (list instanceof Collection) {
            this.navigatePages = navigatePages;
            //计算导航页
            calcNavigatepageNums();
            //计算前后页,第一页,最后一页
            calcPage();
            //判断页面边界
            judgePageBoudary();
        }
    }
.......
}

你可能感兴趣的:(数据库知识,mybatis)