Mybatis笔记

Mybatis

0.从JDBC谈起

创建maven项目

0.1 准备数据
DROP TABLE IF EXISTS tb_user;
CREATE TABLE tb_user (
id bigint auto_increment,
user_name varchar(32) DEFAULT NULL,
password varchar(32) DEFAULT NULL,
name varchar(32) DEFAULT NULL,
age int(10) DEFAULT NULL,
sex int(2) DEFAULT NULL,
birthday date DEFAULT NULL,
created datetime DEFAULT NULL,
updated datetime 
    DEFAULT NULL,
PRIMARY KEY (id)
);

INSERT INTO tb_user ( user_Name, password, name, age, sex, birthday, created, updated) VALUES ( 'zpc', '123456', '鹏程', '22', '1', '1990-09-02', sysdate(), sysdate());
INSERT INTO tb_user ( user_Name, password, name, age, sex, birthday, created, updated) VALUES ( 'hj', '123456', '静静', '22', '1', '1993-09-05', sysdate(), sysdate());
0.2 引入依赖
<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

1.JDBC回顾

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @author yinzhenn
 */
public class JDBCTest {
    public static void main(String[] args) throws Exception {
        Connection connection = null;
        PreparedStatement prepareStatement = null;
        ResultSet rs = null;

        try {
            // 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获取连接
            String url = "jdbc:mysql://127.0.0.1:3306/mybatis_yzn";
            String user = "root";
            String password = "root";
            connection = DriverManager.getConnection(url, user, password);
            // 获取statement,preparedStatement
            String sql = "select * from tb_user where id= ?";
            prepareStatement = connection.prepareStatement(sql);
            // 设置参数
            prepareStatement.setLong(1, 1l);
            // 执行查询
            rs = prepareStatement.executeQuery();
            // 处理结果集
            while (rs.next()) {
                System.out.println(rs.getString("user_name"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getInt("age"));
                System.out.println(rs.getDate("birthday"));
            }
        } finally {
            // 关闭连接,释放资源
            if (rs != null) {
                rs.close();
            }
            if (prepareStatement != null) {
                prepareStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

2.JDBC缺点分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gI1Vfa0R-1573125920244)(/20180701220146135.png)]

3.Mybatis框架介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EYhOCT2H-1573125920247)(/20180701220221392-1570330675031.png)]

框架可以理解为一个半成品的软件,它的内部已经写好了一些常用的功能,但额外的功能需要我们自己去实现,框架已经把一些常用的功能自己封装好了

但框架中一些没有封装的代码(变量),需要框架使用者自己在 xml 文件中去定义(这其中涉及了xml解析技术和反射技术)

官方文档 :https://mybatis.org/mybatis-3/getting-started.html

3.1Mybaits整体架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4W2auIJL-1573125920249)(/20180701220241831.png)]

4. 快速入门

4.1 引入依赖
<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>
4.2 全局配置文件(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>
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_yzn?useUnicode=true&characterEncoding=utf-8&useSSL=true"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

   <!-- 环境,可以配置多个,default:指定采用哪个环境 -->
   <environments default="test">
      <!-- id:唯一标识 -->
      <environment id="test">
         <!-- 事务管理器,JDBC类型的事务管理器 -->
         <transactionManager type="JDBC" />
         <!-- 数据源,池类型的数据源 -->
         <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_yzn" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
         </dataSource>
      </environment>
      <environment id="development">
         <!-- 事务管理器,JDBC类型的事务管理器 -->
         <transactionManager type="JDBC" />
         <!-- 数据源,池类型的数据源 -->
         <dataSource type="POOLED">
            <!-- 配置了properties,所以可以直接引用 -->
            <property name="driver" value="${driver}" /> 
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
         </dataSource>
      </environment>
   </environments>
</configuration>
4.3 配置mapper,创建实体类
package org.neuedu.mybatis.bean;

import java.util.Date;

public class User {
    private String id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private String created;
    private String updated;
	// getter,setter,toString...
}
<?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 命名空间,随意起,但不能重复 -->
<mapper namespace="usermapper">
    <!-- 
		sql 语句
		select 表示功能做的是查询
		id 是为这个查询起个名字
		resultType 查询出来的结果用什么对象进行封装,但目前需要查询出来的字段与属性名相同,否则映射不上
 	-->
    <select id="a" resultType="org.neuedu.mybatis.bean.User">
        select * from tb_user where id = #{id}
    </select>
</mapper>
4.4 修改全局配置文件(mybatis-config.xml)

配上UserMapper.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>
    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_yzn" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
    <!-- 配置mapper映射 -->
    <mappers>
        <!-- 这里不要用 . -->
        <mapper resource="org/neuedu/mybatis/mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>
4.5 构建sqlSessionFactory(MybatisTest.java)
// 指定全局配置文件
String resource = "mybatis-config.xml";
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
4.6 打开sqlSession会话,并执行sql(MybatisTest.java)
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 操作CRUD,第一个参数:指定statement,规则:命名空间+“.”+statementId
// 第二个参数:指定传入sql的参数:这里是用户id
User user = sqlSession.selectOne("usermapper.a", 1);
System.out.println(user);

完整代码

package org.neuedu.mybatis;

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 org.neuedu.mybatis.bean.User;

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

public class MybatisTest {
    public static void main(String[] args) {
        // 指定全局配置文件
        String resource = "mybatis-config.xml";
        // 读取配置文件
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            // 构建sqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 获取sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 操作CRUD,第一个参数:指定statement,规则:命名空间+“.”+statementId
            // 第二个参数:指定传入sql的参数:这里是用户id
            User user = sqlSession.selectOne("usermapper.a", 1);
            System.out.println(user);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKpmiPqE-1573125920251)(/1570337307322.png)]

启动运行测试会报错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3oDWE7vw-1573125920252)(/1570337422874.png)]

原因是我们写的 mapper.xml 文件,maven在构建项目时不会进行自动编译,此时我们需要在pom文件中指定在构建项目时需要包含 *.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.neuedu</groupId>
    <artifactId>mybatis_yzn</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

启动测试,OK!

5.分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JkBCbYBg-1573125920254)(/1570338007313.png)]

5.1 引入日志依赖包(pom.xml)

会自动引入log4j以及slf4j-api

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
</dependency>
5.2 添加log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

再次运行会打印日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tS5oKcFE-1573125920256)(/1570338050063.png)]

5.3 MyBatis使用步骤总结

配置mybatis-config.xml 全局的配置文件 (1、数据源,2、外部的mapper)

创建SqlSessionFactory

通过SqlSessionFactory创建SqlSession对象

通过SqlSession操作数据库 CRUD【create,read,update,delete】

调用session.commit()提交事务

调用session.close()关闭会话

####5.4 解决数据库字段名和实体类属性名不一致的问题

解决方案1:取别名

解决方案2:参考后面的resultMap —— mapper具体的配置的时候

解决方案3:参考驼峰匹配 —— mybatis-config.xml 的时候

6.动态代理Mapper实现类

6.1思考上述CRUD中的问题

在做数据库访问时,我们都有相对应的接口

以前我们的方式是 :接口定义方法 – 实现类实现方法

现在有了mybatis貌似可以变成 :接口定义方法 – 实现类(调用sqlSession完成CRUD) – mapper 文件

当然可以,但还可以更精简!!!

**接口定义方法 – 用 mapper.xml 充当以前的实现类 **

6.2 使用动态代理改造CRUD

如果希望使用mybatis通过的动态代理的接口,就需要namespace中的值,和需要对应的Mapper(dao)接口的全路径一致。

6.2.1 项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DxsaUOzP-1573125920258)(/1570349283945.png)]

#####6.2.2 UserMapper.java

package org.neuedu.mybatis.mapper;

import org.neuedu.mybatis.bean.User;

public interface UserMapper {
    User queryUserById(Integer id);
}
6.2.3 UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.neuedu.mybatis.mapper.UserMapper">
    <select id="queryUserById" resultType="org.neuedu.mybatis.bean.User" parameterType="Integer">
        select id,user_name as userName,password,name,age,birthday,sex,created,updated
        from tb_user
        where id = #{id};
    </select>
</mapper>
6.2.4 MybatisTest.java
package org.neuedu.mybatis;

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 org.neuedu.mybatis.bean.User;
import org.neuedu.mybatis.mapper.UserMapper;

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

public class MybatisTest {
    public static void main(String[] args) {
        // 指定全局配置文件
        String resource = "mybatis-config.xml";
        // 读取配置文件
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            // 构建sqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 获取sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // --------------------------------------------------------------
            // 利用动态代理获取对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // --------------------------------------------------------------
            User user = mapper.queryUserById(1);
            System.out.println(user);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6.2.5 mapper 映射器改造

因为我们的mapper文件是放在同一个包下的,一个一个映射太麻烦了

mybatis为我们提供了另一种配置方式

mybatis-config.xml

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.neuedu.mybatis.mapper"/>
</mappers>
6.3 动态代理总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UBEtm1MG-1573125920259)(/20180701222239762.png)]

7.mybatis-config.xml详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iA0N2hr8-1573125920261)(/20180701222257828.png)]

7.1 properties属性读取外部资源

properties配置的属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。例如:

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_yzn?useSSL=true
jdbc.username=root
jdbc.password=root

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>
    <!-- 引入外部资源 -->
    <properties resource="db.properties"></properties>
    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <!-- ${} 获取变量 -->
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="org.neuedu.mybatis.mapper"/>
    </mappers>
</configuration>
7.2 settings设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWy7spcI-1573125920262)(/20180701222516974.png)]

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
7.3 typeAliases设置
<typeAliases>
    <typeAlias type="org.neuedu.mybatis.bean.User" alias="User"/>
</typeAliases>

添加此配置后

mapper文件的返回值如果是User,可以用别名代替

但实体类较多时,建议如下配置

<typeAliases>
    <!-- 为 org.neuedu.mybatis.bean 包下所有类批量定义别名,默认是他们自己的类名-->
    <package name="org.neuedu.mybatis.bean"/>
</typeAliases>

8.Mapper XML文件详解

8.1 CRUD标签

#####8.1.1.select

select – 书写查询sql语句
select中的几个属性说明:
id属性:当前名称空间下的statement的唯一标识。必须。要求id和mapper接口中的方法的名字一致。
resultType:将结果集映射为java的对象类型。必须(和 resultMap 二选一)
parameterType:传入参数类型。可以省略

<insert id="addUser" parameterType="User" >
        <!-- 返回新插入记录的主键值 -->
    <selectKey keyProperty="id" order="AFTER" resultType="int">
        select LAST_INSERT_ID()
    </selectKey>
    insert into user(username, birthday, sex, address)
    values(#{username}, #{birthday}, #{sex}, #{address})
</insert>

#####8.1.2.insert

insert 的几个属性说明:
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
useGeneratedKeys:开启主键回写
keyColumn:指定数据库的主键
keyProperty:主键对应的pojo属性名
标签内部:具体的sql语句。

#####8.1.3.update

id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。

#####8.1.4.delete

delete 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。

8.2.#{}和${}

当我们使用#{}

<mapper namespace="org.neuedu.mybatis.mapper.UserMapper">
    <select id="queryUserById" resultType="User">
        select id,user_name,password,name,age,birthday,sex,created,updated
        from tb_user
        where id = #{id};
    </select>
</mapper>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0uNoTjO-1573125920264)(/1570351891478.png)]

注意:

#{} 只是替换?,相当于PreparedStatement使用占位符去替换参数,可以防止sql注入,而且替换站位符后是一个带双引号的参数 例如 :id = "1" ,在有些时候带双引号就会报错

场景:数据库有两个一模一样的表。历史表,当前表 查询表中的信息,有时候从历史表中去查询数据,有时候需要去新的表去查询数据。 希望使用1个方法来完成操作。

<select id="queryUserByTableName" resultType="org.neuedu.mybatis.bean.User">
    select * from #{tableName}
</select>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cghDEX9N-1573125920265)(/20180701223229114.png)]

有问题,报语法错误:相当于执行了这样一条sql: select * from "tb_user"; 显然表名多了引号。

改正:

<select id="queryUserByTableName" resultType="org.neuedu.mybatis.bean.User">
    select * from ${tableName}
</select>

${} 是进行字符串拼接,相当于sql语句中的Statement,使用字符串去拼接sql;$可以是sql中的任一部分传入到Statement中,不能防止sql注入。

使用${} 去取出参数值信息,需要使用${value}

#{} 只是表示占位,与参数的名字无关,如果只有一个参数,会自动对应。

#{}多个参数时

/**
 * 登录(直接使用注解指定传入参数名称)
 *
 * @param userName
 * @param password
 * @return
 */
public User login(@Param("userName") String userName, @Param("password") String password);

<select id="login" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user where user_name = #{userName} and password = #{password}
</select>
8.3 面试题(#、$区别)

#{}是代替占位符,能防止sql注入

#{} 只是表示占位,与参数的名字无关,如果只有一个参数,会自动对应。

${} 是进行字符串拼接,$可以是sql中的任一部分传入到Statement中,不能防止sql注入

使用${} 去取出参数值信息,需要使用${value}

/**
 * #号
 * @param username1
 * @return
 */
User queryUserListByName1(@Param("username1") String username1);

/**
 * $号
 * @param username2
 * @return
 */
User queryUserListByName2(@Param("username2") String username2);

<select id="queryUserListByName1" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user WHERE user_name=#{username1}
</select>

<select id="queryUserListByName2" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user WHERE user_name='${username2}'// 需要手动加引号
</select>

####8.4 resultMap

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R2rSZ2HY-1573125920267)(/2018070122370824.png)]

<?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="org.neuedu.mybatis.mapper.UserMapper">
   <!-- resultMap 随意起名 -->
   <select id="queryUserById" resultMap="BasicResultMap">
       select id,user_name,password,name,age,birthday,sex,created,updated
       from tb_user
       where id = #{id};
   </select>
   <!-- id 与 需要映射的resultMap 想匹配  -->
   <resultMap id="BasicResultMap" type="User">
       <!--
   		id 标签指定主键
   		property 指定实体类属性名
   		column 数据库查出的字段名
   	-->
       <id property="id" column="id"></id>
       <result property="userName" column="user_name"></result>
       <result property="password" column="password"></result>
       <result property="name" column="name"></result>
       <result property="age" column="age"></result>
       <result property="birthday" column="birthday"></result>
       <result property="sex" column="sex"></result>
       <result property="created" column="created"></result>
       <result property="updated" column="updated"></result>
   </resultMap>
</mapper>
8.5 sql片段
<sql id=""></sql>
<include refId="" />

例如在UserMapper.xml中定义如下片段:

<sql id="commonSql">
		id,
		user_name,
		password,
		name,
		age,
		sex,
		birthday,
		created,
		updated	
</sql> 

则可以在UserMapper.xml中使用它:

<select id="queryUserById" resultMap="userResultMap">
	select <include refid="commonSql"></include> from tb_user where id = #{id}
</select>

9.动态SQL

场景:查询男性用户,如果输入了姓名,按姓名模糊查询

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LAQkjIx1-1573125920269)(/20180701224214925.png)]

9.1.if

场景:查询男性用户,如果输入了姓名,则按姓名查询

定义接口:

/**
 * 查询男性用户,如果输入了姓名,则按姓名查询
 * @param name
 * @return
 */
List<User> queryUserList(@Param("name") String name);

编写mapper

<select id="queryUserList" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user WHERE sex=1
    <if test="name!=null and name.trim()!=''">
      and name like '%${name}%'
    </if>
</select>
9.2.choose when otherwise

场景:查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找,否则查找姓名为“鹏程”的用户。

定义接口:

/**
 * 查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找,否则查找姓名为“鹏程”的用户。
 * @param name
 * @param age
 * @return
 */
List<User> queryUserListByNameOrAge(@Param("name") String name,@Param("age") Integer age);

编写mapper配置:

<select id="queryUserListByNameOrAge" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user WHERE sex=1
    <!--
    	1.一旦有条件成立的when,后续的when则不会执行
    	2.当所有的when都不执行时,才会执行otherwise
    -->
    <choose>
        <when test="name!=null and name.trim()!=''">
            and name like '%${name}%'
        </when>
        <when test="age!=null">
            and age = #{age}
        </when>
        <otherwise>
            and name='鹏程'
        </otherwise>
    </choose>
</select>
9.3.where和set,trim(了解)

场景一:查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询,如果两者都输入,两个条件都要成立。

/**
 * 查询所有用户,如果输入了姓名按照姓名进行模糊查询,如果输入年龄,按照年龄进行查询,如果两者都输入,两个条件都要成立
 * @param name
 * @param age
 * @return
 */
List<User> queryUserListByNameAndAge(@Param("name") String name,@Param("age") Integer age);

编写mapper配置:

<select id="queryUserListByNameAndAge" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user
    <!--如果多出一个and,会自动去除,如果缺少and或者多出多个and则会报错-->
    <where>
        <if test="name!=null and name.trim()!=''">
            and name like '%${name}%'
        </if>
        <if test="age!=null">
            and age = #{age}
        </if>
    </where>
</select>

如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

场景二:修改用户信息,如果参数user中的某个属性为null,则不修改。

接口:

/**
 * 根据id更新用户信息
 * @param user
 */
public void updateUser(User user);

编写mapper配置:

<update id="updateUser" parameterType="org.neuedu.mybatis.bean.User">
    UPDATE tb_user
    <set>
        <if test="userName!=null">user_name = #{userName},</if>
        <if test="password!=null">password = #{password},</if>
        <if test="name!=null">name = #{name},</if>
        <if test="age!=null">age = #{age},</if>
        <if test="sex!=null">sex = #{sex},</if>
        <if test="birthday!=null">birthday = #{birthday},</if>
        updated = now(),
    </set>
    WHERE
    (id = #{id});
</update><update id="updateUser" parameterType="org.neuedu.mybatis.bean.User">
    UPDATE tb_user
    <trim prefix="set" suffixOverrides=",">
        <if test="userName!=null">user_name = #{userName},</if>
        <if test="password!=null">password = #{password},</if>
        <if test="name!=null">name = #{name},</if>
        <if test="age!=null">age = #{age},</if>
        <if test="sex!=null">sex = #{sex},</if>
        <if test="birthday!=null">birthday = #{birthday},</if>
        updated = now(),
    </trim>
    WHERE
    (id = #{id});
</update>
9.4.foreach

动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候

场景:按照多个id查询用户信息

接口 :

/**
 * 按多个Id查询
 * @param ids
 * @return
 */
List<User> queryUserListByIds(@Param("ids") String[] ids);

配置:

<select id="queryUserListByIds" resultType="org.neuedu.mybatis.bean.User">
    select * from tb_user where id in
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</select>

10.缓存(了解)

10.1.一级缓存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rZhaz1Wh-1573125920271)(/2018070122452413.png)]

在mybatis中,一级缓存默认是开启的,并且一直无法关闭

一级缓存满足条件:

1、同一个session中

2、相同的SQL和参数

执行update、insert、delete的时候,会清空缓存

10.2.二级缓存

mybatis 的二级缓存的作用域是一个mapper的namespace ,同一个namespace中查询sql可以从缓存中命中。

在 mapper 文件中开启二级缓存:

<mapper namespace="org.neuedu.mybatis.mapper.UserMapper">
    <cache/>
    <select ...>
    	...
    </select>
</mapper>

开启二级缓存,必须序列化:

public class User implements Serializable {}

测试:

package org.neuedu.mybatis;

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 org.neuedu.mybatis.bean.User;
import org.neuedu.mybatis.mapper.UserMapper;

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

public class MybatisTest {
    public static void main(String[] args) {
        // 指定全局配置文件
        String resource = "mybatis-config.xml";
        // 读取配置文件
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            // 构建sqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 获取sqlSession
            // 第1个 sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
            User user1 = mapper1.queryUserById(1);
            sqlSession.close();
		   // 第2个 sqlSession
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
            UserMapper mapper2 = sqlSession1.getMapper(UserMapper.class);
            User user2 = mapper2.queryUserById(1);
            System.out.println(user1);
            System.out.println(user2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

查看日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Csukal1f-1573125920272)(/1570363540954.png)]

关闭二级缓存: 不开启,或者在全局的mybatis-config.xml 中去关闭二级缓存

<settings>
    <!--开启驼峰匹配-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--开启二级缓存,全局总开关,这里关闭,mapper中开启了也没用-->
    <setting name="cacheEnabled" value="false"/>
</settings>

###11.高级查询

11.1.表关系说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gxa4LIFc-1573125920274)(/20180701225531901.png)]

数据库脚本

CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO tb_order VALUES ('1', '2', '201807010001', '2018-07-01 19:38:35', '2018-07-01 19:38:40');

CREATE TABLE tb_item (
id int(11) NOT NULL,
itemName varchar(255) DEFAULT NULL,
itemPrice decimal(10,2) DEFAULT NULL,
itemDetail varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO tb_item VALUES ('1', '袜子', '29.90', '香香的袜子');
INSERT INTO tb_item VALUES ('2', '鞋子', '99.99', 'Nike的鞋');

CREATE TABLE tb_orderdetail (
id int(11) NOT NULL AUTO_INCREMENT,
order_id int(11) DEFAULT NULL,
total_price decimal(10,0) DEFAULT NULL,
item_id int(11) DEFAULT NULL,
status int(10) unsigned zerofill DEFAULT NULL COMMENT '0成功,非0失败',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO tb_orderdetail VALUES ('1', '1', '10000', '1', '0000000001');
INSERT INTO tb_orderdetail VALUES ('2', '1', '2000', '2', '0000000000');

对应实体类

public class Order {
   private Integer id;
   private Long userId;
   private String orderNumber;
   private Date created;
   private Date updated;
}

需求说明:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lyZCkq29-1573125920275)(/20180701225549367.png)]

11.2.一对一查询

一对一查询 : 查询订单,并查出下单人的信息

**方法一:核心思想扩展Order对象,来完成映射 **

新建OrderUser实体类继承Order:

public class OrderUser extends Order {
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;
}

OrderMapper接口:

public interface OrderMapper {
     OrderUser queryOrderUserByOrderNumber(@Param("number") String number);
}

配置OrderMapper:

<mapper namespace="org.neuedu.mybatis.mapper.OrderMapper">
    <select id="queryOrderUserByOrderNumber" resultType="org.neuedu.mybatis.OrderUser">
      select * 
      from tb_order o 
      left join tb_user u 
      on o.user_id=u.id 
      where o.order_number = #{number}
   </select>
</mapper>

**方法二:面向对象的思想,在Order对象中添加User对象。 **

在Order对象中添加User属性:

public class Order {
    private Integer id;
    private Long userId;
    private String orderNumber;
    private Date created;
    private Date updated;
    private User user;
}

接口:

/**
 * 根据订单号查询订单用户的信息
 * @param number
 * @return
 */
Order queryOrderWithUserByOrderNumber(@Param("number") String number);

使用resultType不能完成自动映射,需要手动完成结果集映射resultMap:

<resultMap id="OrderUserResultMap" type="org.neuedu.mybatis.bean.Order" autoMapping="true">
     <id column="id" property="id"/>
     <!--association:完成子对象的映射-->
     <!--property:子对象在父对象中的属性名-->
     <!--javaType:子对象的java类型-->
     <!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
     <association property="user" javaType="org.neuedu.mybatis.bean.User" autoMapping="true">
         <id column="user_id" property="id"/>
     </association>
 </resultMap>

 <select id="queryOrderWithUserByOrderNumber" resultMap="OrderUserResultMap">
   	select * 
    from tb_order o 
    left join tb_user u 
    on o.user_id=u.id 
    where o.order_number = #{number}
</select>
11.3.一对多查询

一对多查询:查询订单,查询出下单人信息并且查询出订单详情。

Order类:

public class Order {
    private Integer id;
    private Long userId;
    private String orderNumber;
    private Date created;
    private Date updated;
    private User user;
    private List<OrderDetail> detailList;
}
public class OrderDetail {
    private Integer id;
    private Integer orderId;
    private Double totalPrice;
    private Integer status;
}

接口:

/**
 * 根据订单号查询订单用户的信息及订单详情
 * @param number
 * @return
 */
Order queryOrderWithUserAndDetailByOrderNumber(@Param("number") String number);

Mapper映射:

<resultMap id="OrderUserDetailResultMap" 
           type="org.neuedu.mybatis.bean.Order" 
           autoMapping="true">
    <id column="id" property="id"/>
    <!--collection:定义子对象集合映射-->
    <!--association:完成子对象的映射-->
    <!--property:子对象在父对象中的属性名-->
    <!--javaType:子对象的java类型-->
    <!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
    <association property="user" javaType="org.neuedu.mybatis.bean.User" autoMapping="true">
        <id column="user_id" property="id"/>
    </association>
    <collection 
                property="detailList" 
                javaType="List" 
                ofType="org.neuedu.mybatis.bean.OrderDetail" 
                autoMapping="true">
        <id column="id" property="id"/>
    </collection>
</resultMap>

 <select id="queryOrderWithUserAndDetailByOrderNumber" resultMap="OrderUserDetailResultMap">
   select * 
   from tb_order o
   left join tb_user u on o.user_id=u.id
   left join tb_orderdetail od on o.id=od.order_id
   where o.order_number = #{number}
</select>
11.4.多对多查询

多对多查询:查询订单,下单人信息并且查询出订单详情中的商品数据。

public class OrderDetail {
    private Integer id;
    private Integer orderId;
    private Double totalPrice;
    private Integer status;
    private Item item;
}
public class Item {
    private Integer id;
    private String itemName;
    private Float itemPrice;
    private String itemDetail;
}

接口:

/**
 * 根据订单号查询订单用户的信息及订单详情及订单详情对应的商品信息
 * @param number
 * @return
 */
Order queryOrderWithUserAndDetailItemByOrderNumber(@Param("number") String number);

Mapper映射:

<resultMap id="OrderUserDetailItemResultMap" type="org.neuedu.mybatis.bean.Order" autoMapping="true">
    <id column="id" property="id"/>
    <association property="user" javaType="org.neuedu.mybatis.bean.User" autoMapping="true">
        <id column="user_id" property="id"/>
    </association>
    <collection property="detailList" 
                javaType="List" 
                ofType="org.neuedu.mybatis.bean.OrderDetail" 
                autoMapping="true">
        <id column="detail_id" property="id"/>
        <association property="item" javaType="org.neuedu.mybatis.bean.Item" autoMapping="true">
            <id column="item_id" property="id"/>
        </association>
    </collection>
</resultMap>

<select id="queryOrderWithUserAndDetailItemByOrderNumber" 
        resultMap="OrderUserDetailItemResultMap">
   select *,od.id as detail_id 
   from tb_order o
   left join tb_user u on o.user_id=u.id
   left join tb_orderdetail od on o.id=od.order_id
   left join tb_item i on od.item_id=i.id
   where o.order_number = #{number}
</select>
11.5.高级查询的整理

当进行多表连接复杂查询时,我们可以有几个方案

1.可以创建新的实体类与查询结果进行映射

2.resutlType无法帮助我们自动的去完成映射,所以只有使用resultMap手动的进行映射,针对一对一,一对多,多对多使用不同的标签进行处理

<resultMap type="Order" id="orderUserLazyResultMap">
	<!--定义pojo中的单个对象的 property 定义对象的属性名, javaType 属性的类型-->
	<association property="user" javaType="User" autoMapping="true">
		<id .../>
	</association>
	<!--如果属性是集合使用collection ,javaType 集合的类型,ofType 表示集中的存储的元素类型-->
	<collection property="details" javaType="List" ofType="OrderDetail" autoMapping="true">
		<id .../>
    </collection>
</resultMap>

12.延迟加载(了解)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifrdUgGM-1573125920279)(/20180701225745158.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G7FU75IU-1573125920280)(/20180701225759457.png)]

编写接口:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aauOMRZh-1573125920281)(/20180701225910938.png)]

Mapper配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7RYOXdT-1573125920283)(/20180701225922599.png)]

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SAIh5YVG-1573125920284)(/20180701225934528.png)]

开启延迟加载:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvoHmbFa-1573125920286)(/20180701230004343.png)]

修改测试用例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fh8MghLq-1573125920290)(/20180701230017939.png)]

执行,报错:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zU28b6tM-1573125920292)(/20180701230031273.png)]

添加cglib:

<dependency>
    <groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.1</version>
</dependency>

执行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H23Zpe0W-1573125920293)(/20180701230048705.png)]

13.逆向工程 Mybatis Generator的使用

可以根据数据库简单创建实体类和dao接口以及mapper的映射文件,逆向工程可能在数据库字段比较少的时候体现不会方便,但是当参与到数据库字段比较多的时候,我们不可能再一个个编写实体类了,此时我们的逆向工程就应运而生了

CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
`create` datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO tb_order VALUES ('1', '2', '201807010001', '2018-07-01 19:38:35', '2018-07-01 19:38:40');

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration        PUBLIC
        "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 数据库驱动包位置,路径请不要有中文-->
    <classPathEntry location="E:\\MavenRepository\\mysql\\mysql-connector-java\\5.1.47\\mysql-connector-java-5.1.47.jar"/>
    <!-- 一个数据库一个context-->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 生成的pojo,将implements Serializable -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
        <!-- 注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
            <!-- <property name="suppressDate" value="true" />  是否生成注释代时间戳 -->
        </commentGenerator>

        <!-- 数据库链接URL、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/mybatis_yzn" userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 类型转换 -->
        <javaTypeResolver>
            <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer true,把JDBC DECIMAL
                和 NUMERIC 类型解析为java.math.BigDecimal -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- 生成model模型,设置对应的包名(targetPackage)和存放路径(targetProject)。targetProject可以指定具体的路径,如./src/main/java,也可以使用MAVEN来自动生成,这样生成的代码会在target/generatord-source目录下 -->
        <javaModelGenerator targetPackage="org.neuedu.mybatis.bean" targetProject="./src/main/java">
            <!-- 是否在当前路径下新加一层schema,eg:false路径com.oop.eksp.user.model 而true:com.oop.eksp.user.model.[schemaName] -->
            <property name="enableSubPackages" value="false"/>
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!--对应的mapper.xml文件 -->
        <sqlMapGenerator targetPackage="org.neuedu.mybatis.mapper" targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 对应的Mapper接口类文件 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="org.neuedu.mybatis.mapper"
                             targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 列出要生成代码的所有表,这里配置的是不生成Example文件 -->
        <!-- schema即为数据库名tableName为对应的数据库表 domainObjectName是要生成的实体类 enable*ByExample是否生成 example类   -->
        <table tableName="tb_order" domainObjectName="Order"
               schema="${gererator.schema}"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
            <!-- 用于指定生成实体类时是否使用实际的列名作为实体类的属性名。false是 Camel Case风格-->
            <property name="useActualColumnNames" value="false"/>
        </table>
    </context>
</generatorConfiguration>

pom.xml添加插件依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.neuedu</groupId>
    <artifactId>mybatis_yzn</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
        <!-- mybatis逆向工程 -->
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tUjuiKak-1573125920295)(/1570373849219.png)]

启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBrukIgM-1573125920296)(/1570375945999.png)]

14.常见笔面试题

xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
4.0.0

<groupId>org.neuedu</groupId>
<artifactId>mybatis_yzn</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.7</version>
    </dependency>
</dependencies>

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
    <!-- mybatis逆向工程 -->
    <plugins>
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.2</version>
            <configuration>
                <verbose>true</verbose>
                <overwrite>true</overwrite>
            </configuration>
        </plugin>
    </plugins>
</build>
```

[外链图片转存中…(img-tUjuiKak-1573125920295)]

启动

[外链图片转存中…(img-NBrukIgM-1573125920296)]

14.常见笔面试题

https://www.cnblogs.com/lukelook/p/11099039.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值