MyBatis知识点总结

Lou.Chen
大约 25 分钟

MyBatis 3.5.5

https://mybatis.org/mybatis-3/zh/index.htmlopen in new window

一、MyBatis基本环境搭建

1、pom.xml

<dependencies>
    <!--日志打印-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <version>2.11.0</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.18</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.4</version>
    </dependency>
  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
        </includes>
      </resource>
    </resources>
  </build>

2、实体

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {
    private static final long serialVersionUID = -24165170760748761L;
    
    private Integer id;
    
    private String empName;
    
    private String empGender;
    
    private String email;
    
    private Date birthday;
    
    private Date updatetime;
    
    private Date createtime;

}

3、Dao

public interface EmployeeDao {

     Employee getEmployeeById(Integer id);

    int addEmployee(Employee employee);

    int deleteEmployeeById(Integer id);

    int updateEmployee(Employee employee);
}

4、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.lc.dao.EmployeeDao">

    <!--增删改无需写返回类型。 自动接收返回影响的行数即可-->
    <!--如果是boolean 影响0行自动封装为false,否则为true-->
    <insert id="addEmployee">
        insert into employee(emp_name,emp_gender,email,birthday,updatetime,createtime) values(#{empName},#{empGender},#{email},#{birthday},#{updatetime},#{createtime})
    </insert>

    <update id="updateEmployee">
        update employee set emp_name=#{empName},emp_gender=#{empGender},email=#{email},birthday=#{birthday}
    </update>

    <delete id="deleteEmployeeById">
        delete from employee where id=#{id}
    </delete>

    <!--查询需要写返回类型-->
    <select id="getEmployeeById" resultType="Employee">
        select * from employee where id=#{id};
    </select>

</mapper>

5、jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false

6、log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="INFO">
    <appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <RollingFile name="RollingFile" fileName="logs/app.log"
                     filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="5 MB"/>
        </RollingFile>
    </appenders>
    <loggers>
        <root level="DEBUG">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFile"/>
        </root>
    </loggers>
</configuration>

核心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>

    <!--和spring中的一样:<context:property-placeholder location="classpath:jdbc.properties" />-->
    <!--引入外部的jdbc配置文件
        resource:从类路径获取
        url:从磁盘或者网络资源路径
    -->
    <properties resource="jdbc.properties"></properties>

    <!--这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。-->
    <settings>
        <!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。-->
        <!--数据库中的字段一般不需要大写,到大写的字母之前加下划线即可,开启后 视图bean直接以驼峰命名即可-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--为类型起别名-->
    <typeAliases>
        <!--默认别名为 '类名'
          alias:起别名
        -->
        <!--一次只能指定一个类型的别名-->
        <!--<typeAlias type="org.lc.entity.Employee" alias="e"/>-->

        <!--推荐全类名,不用别名-->
        <!--为该包下的所有都起别名 默认为类名-->
        <package name="org.lc.entity"/>
    </typeAliases>

    <!--自定义类型处理器-->
    <!--<typeHandlers>-->
    <!--    <typeHandler handler=""-->
    <!--</typeHandlers>-->

    <!--配置运行的environments环境-->
    <!--配置 事务管理器和数据库连接池(默认使用JDBC的数据源和事务管理器)-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置连接池-->
            <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>

    <!--mybatis用来考数据库移植的-->
    <!--type: 固定写法-->
    <databaseIdProvider type="DB_VENDOR">
        <!--name:数据库厂商标识  value:别名-->
        <property name="MySQL" value="mysql"/>
        <property name="SQL Server" value="sqlserver"/>
        <property name="Oracle" value="oracle"/>
    <!--    mapper中的使用 通过databaseId指定即可-->
    <!-- <select id="getEmployeeById" resultType="Employee" databaseId="oracle">
        select * from employee where id=#{id};
         </select>-->
    </databaseIdProvider>

    <!--映射接口的实现文件-->
    <mappers>
        <!--
            resource: 从类路径映射的xml
            url:引用磁盘或网络路径
            class: 接口的全类名
        -->
        <!--一次只能映射一个mapper,xml文件必须放在在resources文件夹下-->
        <!--<mapper resource="mapper/EmployeeDao.xml"></mapper>-->

        <!--一次只能映射一个接口,若映射指定接口,则需要将xml放在和接口同包下,且名称必须相同。并且需要在maven配置中过滤掉xml文件-->
        <!--<mapper class="org.lc.dao.EmployeeDao"></mapper>-->

        <!--映射该包下的所有接口,需要将xml文件和接口放在一起,但是我们还是想将xml放在resources下,则需要在
         resources下建一个和接口同样的包名,等编译打包之后会合并在一起
         注意:建包的时候需要一级一级的键。一起键会当做一个包
        -->
        <package name="org.lc.dao"/>

    </mappers>

</configuration>

测试

public class T1 {

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    static SqlSessionFactory sqlSessionFactory=null;
    static {
        //1、根据全局配置文件创建一个SqlsessionFactory
        //SqlSessionFactory是SqlSession的工厂,用于创建SqlSession对象
        //SqlSession:sql会话(代表和数据库的一次会话)
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
         sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void Test() throws IOException {
        //2、获取数据库的一次会话 相当于getConnection
        //默认jdbc为手动提交,需要传入true自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            //3、使用SqlSession操作数据库,获取到dao的实现接口
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            //调用接口的方法
            System.out.println(mapper.getEmployeeById(1));
        } finally {
            //或者在后面设置自动提交
            // sqlSession.commit();
            sqlSession.close();
        }
    }
    @Test
    public void Test1() throws ParseException {
        //2、获取数据库的一次会话 相当于getConnection
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            //3、使用SqlSession操作数据库,获取到dao的实现接口
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
           mapper.addEmployee(new Employee(null, "张三4","男","42119@qq.com",simpleDateFormat.parse("1999-09-09"),new Date(),new Date()));
        } finally {
            // sqlSession.commit();
            sqlSession.close();
        }
    }
}

二、SQL映射文件

1、插入后获取自增主键的值

    <!--
        useGeneratedKeys: 是否使用自增的主键
        keyProperty:将获取的主键值 赋值给那个属性
    -->
    <insert id="addEmployee" useGeneratedKeys="true" keyProperty="id">
        insert into employee(emp_name,emp_gender,email,birthday,updatetime,createtime) values(#{empName},#{empGender},#{email},#{birthday},#{updatetime},#{createtime})
    </insert>
    @Test
    public void Test1() throws ParseException {
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
 
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            Employee employee = new Employee(null, "张三5", "男", "42119@qq.com", simpleDateFormat.parse("1999-09-09"), new Date(), new Date());
            mapper.addEmployee(employee);
            //封装到id属性中
            System.out.println("自增的id:"+employee.getId());
        } finally {
            sqlSession.close();
        }
    }

2、插入前获取自增主键的值

    <insert id="addEmployee2">
--         resultType:返回查询的类型
--         keyProperty: 赋值给指定bean的属性
--         order:在sql执行前运行。查询出来的值会赋值给bean中id属性后再运行sql
         <selectKey resultType="integer" keyProperty="id" order="BEFORE">
             select max(id)+1 from employee
         </selectKey>
        insert into employee(id,emp_name,emp_gender,email,birthday,updatetime,createtime) values(#{id},#{empName},#{empGender},#{email},#{birthday},#{updatetime},#{createtime})
    </insert>

   @Test
    public void Test1() throws ParseException {
        //2、获取数据库的一次会话 相当于getConnection
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            //3、使用SqlSession操作数据库,获取到dao的实现接口
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            Employee employee = new Employee(null, "张三6", "男", "42119@qq.com", simpleDateFormat.parse("1999-09-09"), new Date(), new Date());
            mapper.addEmployee2(employee);
            System.out.println("获取执行sql前的id:"+employee.getId());
        } finally {
            // sqlSession.commit();
            sqlSession.close();
        }
    }

3、传入各种参数和取值@param

1)单个参数

①基本类型 Employee getEmployeeById(Integer id);

  • 取值:#{id}

②引用类型

  • JavaBean 对象 int addEmployee(Employee employee);

    • 取值:#{Employee的属性名} 例:#{empName}
  • 数组对象 int deleteMultipleEmps(@Param("id") Integer[] id); 必须加上**@Param("id")**,并指定参数名称

    •     <delete id="deleteMultipleEmps">
              delete from employee where id in
              <foreach collection="id" item="i" separator="," open="(" close=")">
                  #{i}
              </foreach>
          </delete>
      
    • 或者直接通过索引拿

    • delete from employee where id=#{id[0]} and #{id[1]}
      
  • List集合 int addEmployeeList(@Param("list") List<Employee> list); 必须加上**@Param("list")**,并指定参数名称

    •  <insert id="addEmployeeList">
              insert into employee(name, gender, birthday, idCard) values
              <foreach collection="list" item="emp" separator=",">
                  (#{emp.name}, #{emp.gender},#{emp.birthday},#{emp.idCard})
              </foreach>
          </insert>
      
  • Map集合 Employee getEmployeeById2(Map<String,Object> map);

    实际上我们所有的参数都封装为map集合 直接通过map的key取值 例如: #{key值}

    <select id="getEmployeeById2" resultType="org.lc.entity.Employee">
            select * from employee where id=#{id} and emp_name=#{empName}
    </select>
    
                EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
                //调用接口的方法
                HashMap<String,Object> map=new HashMap<>();
                map.put("id", "1");
                map.put("empName", "张三");
                System.out.println(mapper.getEmployeeById2(map));
    
2)多个参数

①基本类型 int updatePassword(@Param("encodepass") String encodepass,@Param("hrid") Integer hrid); 必须都加上**@param**并为其指定别名

  • 取值:#{encodepass} , #{hrid}

②不同类型 Long getTotal(@Param("employee") Employee employee,@Param("beginDateScope") Date[] beginDateScope); 同时指定**@param**注解并为其取别名

  • javaBean 取值 #{别名.属性名} 例如:#{employee.empName}
  • 数组取值:#{beginDateScope[0]} 或者 foreach遍历取值
  • 基本类型 :#{别名}

③Map集合+其他类型 Employee getEmployeeById2(@Param("map") Map<String,Object> map,@Param("gender") String gender); 必须都加上**@param**并为其指定别名

直接通过 map . 键值获取 例如: #{map.键值}

<select id="getEmployeeById2" resultType="org.lc.entity.Employee">
        select * from employee where id=#{map.id} and emp_name=#{map.empName} and emp_gender=#{gender}
</select>
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            //调用接口的方法
            HashMap<String,Object> map=new HashMap<>();
            map.put("id", "1");
            map.put("empName", "张三");
            System.out.println(mapper.getEmployeeById2(map,"男"));

4、取值时jdbcType的作用

id=#{id,jdbcType=INT}

  • 默认不指定jdbcType,mysql没问题,oracle没问题
  • 如果传入的为null, 则mysql插入null没问题,oracle不指定null到底是什么类型

5、#{} 与 ${} 的区别

#{} : 是参数的预编译方式,参数的位置都是用 ?代替,参数后来都是预编译设置进去的,不会有sql注入问题

${} :不是参数预编译的方式,而是将 参数 直接和sql拼接,存在sql注入问题,不安全。

  • ${} 可以在不支持参数预编译的位置进行取值就使用 ${}。例如:动态注入表名

6、查询返回List集合

List<Employee> getAllEmployee();
    <!--直接指定返回的集合中的类型即可-->
    <select id="getAllEmployee" resultType="org.lc.entity.Employee">
        select * from employee
    </select>

7、增删改无需写返回类型,只需接收执行影响的行数

8、resultType默认返回类型对应的别名

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

9、查询返回Map集合

1)返回单条集合
Map<String, Object> getEmployeeByIdReturnMap(int id);
    <select id="getEmployeeByIdReturnMap" resultType="map">
        select * from employee where id=#{id}
    </select>

返回的map集合为 列名作为key, 值作为value

2)返回多条集合@MapKey
    //MapKey指定value中JavaBean对象的某个属性作为map中的key  (一般我们指定返回值中的主键作为key)
    @MapKey("id")
    Map<Integer, Employee> getAllEmployeeReturnMap();
  <!--resultType返回的类型为 map中的value类型-->
    <select id="getAllEmployeeReturnMap" resultType="org.lc.entity.Employee">
        select * from employee
    </select>
            EmployeeDao mapper = sqlSession.getMapper(EmployeeDao.class);
            Map<Integer, Employee> employeeByIdReturnMap = mapper.getAllEmployeeReturnMap();
            System.out.println(employeeByIdReturnMap.get(1).toString());
            System.out.println(employeeByIdReturnMap);

10、配置驼峰命名法mapUnderscoreToCamelCase

  • 实体属性isParent或者isparent 都可以进行对数据库字段isparent进行映射(mysql关闭区分大小写)

  • 开启驼峰命名后:实体属性isParent 可以对数据库字段is_parent进行自动映射 。或者实体属性vhrIsParent可以对数据库字段vhr_is_parent进行自动映射。若映射失败,则该实体属性字段查询为空。

  • windows下数据库的表名和字段名不区分大小写,但是在Linux区分大小写,我们建议在 数据库表名统一小写,字段名若要大写则前面加下划线 。

    • 正确实例:emp_name 错误实例:empName
  • Mybatis开启驼峰命名法后

    • 生成代码:若采用生成代码则自动 将 数据库的字段名 emp_name 生成对应的 JavaBean属性名 empName
    • 返回结果集:若直接resultType指定JavaBean,则会把 emp_name 映射成 JavaBean属性名 empName,找不到则报错

11、resultMap自定义封装结果集

1)字段属性映射

若驼峰命名法也不能解决返回的结果集,则需要自定义结果集

数据库字段:

bean:

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Hr implements Serializable {
    private static final long serialVersionUID = 177623542882739248L;
    /**
    * hrID
    */
    private Integer id;
    /**
    * 姓名
    */
    private String name;
    /**
    * 手机号码
    */
    private String phone;
    /**
    * 住宅电话
    */
    private String telephone;

}

dao

public interface HrDao {
    Hr getHrById(int id);
}

mapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.lc.dao.HrDao">
    <!--自定义结果集-->
    <!--id:结果集唯一id-->
    <!--type:结果集的javabean类型-->
    <resultMap id="BaseResultMap" type="org.lc.entity.Hr">
        <!--使用id标签标识主键-->
        <!--property: javabean中的属性名 -->
        <!--column: 数据库对应的字段名 -->
        <id property="id" column="hrid"></id>
        <result property="name" column="hrname"/>
        <result property="phone" column="hrphone"/>
        <result property="telephone" column="hrtelephone"/>
    </resultMap>

    <!--resultMap: 指定自定义结果集的id-->
    <select id="getHrById"  resultMap="BaseResultMap">
        select * from hr where hrid=#{id}
    </select>
</mapper>
1)resultMap一对一映射

数据库字段

bean

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Hr implements Serializable {
    private static final long serialVersionUID = 177623542882739248L;
    /**
    * hrID
    */
    private Integer id;
    /**
    * 姓名
    */
    private String name;
    /**
    * 手机号码
    */
    private String phone;
    /**
    * 住宅电话
    */
    private String telephone;

    //一对一关联对象
    private Department department;

}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Department implements Serializable {
    private static final long serialVersionUID = -43971297416251267L;
    
    private Integer id;
    /**
    * 部门名称
    */
    private String name;
    
    private int enabled;

}

dao

public interface HrDao {
    Hr getHrAndDepartment(int hrid);
}

mapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.lc.dao.HrDao">
    <resultMap id="HrAndDepartment" type="org.lc.entity.Hr">
        <id property="id" column="hrid"></id>
        <result property="name" column="hrname"/>
        <result property="phone" column="hrphone"/>
        <result property="telephone" column="hrtelephone"/>
        <!--关联的对象-->
        <!--javaType:对象类型-->
        <association property="department" javaType="org.lc.entity.Department">
            <id property="id" column="depid"></id>
            <result property="name" column="depName"></result>
            <result property="enabled" column="enabled"></result>
        </association>
    </resultMap>
    
    <select id="getHrAndDepartment" resultMap="HrAndDepartment">
         SELECT
            hrId,
            hrName,
            hrPhone,
            hrTelephone,
            d.depId AS depid,
            depName,
            enabled
        FROM
            hr,
            department AS d
        WHERE
            hr.depid = d.depId and hrid=#{hrid}
    </select>

</mapper>

测试

   @Test
    public void Test1(){
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        HrDao mapper = sqlSession.getMapper(HrDao.class);
        Hr hrById = mapper.getHrAndDepartment(5);
        System.out.println(hrById);
        sqlSession.close();
    }
2)resultMap一对多映射

数据库

bean

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Hr implements Serializable {
    private static final long serialVersionUID = 177623542882739248L;
    /**
    * hrID
    */
    private Integer id;
    /**
    * 姓名
    */
    private String name;
    /**
    * 手机号码
    */
    private String phone;
    /**
    * 住宅电话
    */
    private String telephone;

    //一对一关联对象
    private Department department;

    //一对多关联
    private List<Role> roles;

}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Role implements Serializable {
    private static final long serialVersionUID = 457993748452345260L;
    
    private Integer id;
    
    private String name;
    /**
    * 角色名称
    */
    private String namezh;

}

dao

public interface HrDao {

    Hr getHrAndDepartmentAndRole(int hrid);
}

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.lc.dao.HrDao">
    <resultMap id="HrAndDepartmentAndRole" type="org.lc.entity.Hr">
        <id property="id" column="hrid"></id>
        <result property="name" column="hrName"></result>
        <result property="phone" column="hrPhone"></result>
        <result property="telephone" column="hrTelephone"></result>
        <!--一对一对象关联-->
        <!--javaType:指定对象类型-->
        <association property="department" javaType="org.lc.entity.Department">
            <id property="id" column="depid"></id>
            <result property="name" column="depName"></result>
            <result property="enabled" column="enabled"></result>
        </association>
        <!--一对多关联-->
        <!--ofType:指定集合中的类型-->
        <collection property="roles" ofType="org.lc.entity.Role">
            <id property="id" column="rid"></id>
            <result property="name" column="rname"></result>
            <result property="namezh" column="rnamezh"></result>
        </collection>
    </resultMap>
    <select id="getHrAndDepartmentAndRole" resultMap="HrAndDepartmentAndRole">
        select
            hr.hrid as hrid,
            hrName,
            hrPhone,
            hrTelephone,
            d.depId AS depid,
            depName,
            enabled,
            r.id AS rid,
            r.`name` AS rname,
            r.nameZh AS rnamezh
        FROM
            hr
        LEFT JOIN department AS d ON hr.depId = d.depId
        LEFT JOIN hr_role ON hr.hrId = hr_role.hrid
        LEFT JOIN role AS r ON hr_role.rid = r.id where hr.hrid=#{hrid}
    </select>
</mapper>

测试

    @Test
    public void Test2(){
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        HrDao mapper = sqlSession.getMapper(HrDao.class);
        Hr hrById = mapper.getHrAndDepartmentAndRole(3);
        System.out.println(hrById);
        sqlSession.close();
    }

12、分步查询、懒加载(不常用)

    <resultMap id="HrAndDepartmentAndRole1" type="org.lc.entity.Hr">
        <id property="id" column="hrid"></id>
        <result property="name" column="hrName"></result>
        <result property="phone" column="hrPhone"></result>
        <result property="telephone" column="hrTelephone"></result>
        <result property="department.id" column="depid"/>
        <!--一对一对象关联-->
        <!--分布查询 并设置 懒加载(即用到该属性时使用此sql查询)-->
        <!---->
        <association property="department" column="depid" select="通过其他select标签的全类名加方法名 将该column的值作为参数传递给该select查询。并将查询出来的值关联department" fetchType="lazy">
        </association>
        <!--一对多关联-->
        <!--分布查询 并设置 懒加载(即用到该属性时使用此sql查询)-->
        <collection property="roles" select="" column="">
        </collection>
    </resultMap>

在标签内设置外,还可以在mybatis-cofig.xml中配置

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

三、动态SQL

1、xml特殊字符转义

<小于&lt;&#60;
>大于&gt;&#62;
&&符号&amp;&#38;
"双引号&quot;&#34;
©版权&copy;&#169;
®已注册商标&reg;&#174;
商标(美国)&#8482;
×乘号&times;&#215;
÷除号&divide;&#247;

2、dao bean参考

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {
    private static final long serialVersionUID = -24165170760748761L;    
    private Integer id;    
    private String empName;    
    private String empGender;    
    private String email;   
    private Date birthday;    
    private Date updatetime;
    private Date createtime;
}
public interface EmployeeDao {
    //有条件的查询
    List<Employee> getEmployeeBySelective(Employee employee);

    //有添加的新增
    int addEmployeeSelective(Employee employee);

    //有条件的更新
    int updateEmployeeSelective(Employee employee);

    //有条件的删除
    int deleteEmployeeSelective(Employee employee);

    int deleteEmployeeMultiple(@Param("ids") Integer[] ids);

    int addEmployeeList(@Param("list") List<Employee> list);
}

3、where if标签的使用

动态条件查询

下面这种写法,userIdmatchId必传,where条件必然成立。这里的第一个if标签中的and关键字必须

    <select id="findAccount" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM t_match_account
        <where>
            USER_ID = #{userId}
            and MATCH_ID = #{matchId}
            and STATUS = '0'
            <if test="accountType != null and accountType != ''">
                and ACCOUNT_TYPE = #{accountType}
            </if>
        </where>
    </select>

List<Employee> getEmployeeBySelective(Employee employee);

    <select id="getEmployeeBySelective" resultType="org.lc.entity.Employee">
        select * from employee
        <!--若where中的标签有一个条件满足则 自动加where关键字。若没有条件成立则自动去掉where关键字-->
        <!--where会为第一个判断为true的if标签(包括第一个if前面如果有and也会去掉)去掉前面的and关键字-->
        <where>
            <!-- 判断id不为null-->
            <if test="id!=null">
              id=#{id}
            </if>
            <!--判断empName不为null 并且 empName不为空字符串-->
            <if test="empName!=null and empName!=''">
              and emp_name=#{empName}
            </if>
            <!--判断empGender不为null 并且 empGender不为空字符串-->
            <if test="empGender!=null and !empGender.equals('')">
              and emp_gender=#{empGender}
            </if>
            <if test="email!=null and email!=''">
                and email=#{email}
            </if>
            <if test="birthday!=null">
                and birthday > #{birthday}
            </if>
            <!--判断createtime不为null-->
            <!--直接写 < 可能在xml识别为xml语法,需要将小于号转义为 &lt;-->
            <if test="createtime!=null">
                and createtime &lt; #{createtime}
            </if>
            <if test="updatetime!=null">
                and updatetime = #{updatetime}
            </if>
        </where>
    </select>
动态条件删除(慎用)

int deleteEmployeeSelective(Employee employee);

若所有条件不成立则会删除表

    <delete id="deleteEmployeeSelective">
        delete from employee
        <where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="empName!=null and empName!=''">
                and emp_name=#{empName}
            </if>
            <if test="empGender!=null and !empGender.equals('')">
                and emp_gender=#{empGender}
            </if>
            <if test="email!=null and email!=''">
                and email=#{email}
            </if>
            <if test="birthday!=null">
                and birthday > #{birthday}
            </if>
            <if test="createtime!=null">
                and createtime &lt; #{createtime}
            </if>
            <if test="updatetime!=null">
                and updatetime = #{updatetime}
            </if>
        </where>
    </delete>

4、trim if标签的使用

int addEmployeeSelective(Employee employee);

动态条件插入
 <insert id="addEmployeeSelective">
        insert into employee
        <!--去重-->
      	<!--若有某一个条件成立,则加上前缀和后缀,否则trim所有条件失效-->
        <!--prefix 为下面整块sql添加前缀-->
        <!--suffix 为下面整块sql添加后缀-->
        <!--prefixOverrides 为某一个成立的条件去掉的前缀字符-->
        <!--suffixOverrides 为某一个成立的条件去掉的后缀字符-->
        <trim prefix="(" suffix=")" suffixOverrides="," >
            <if test="id!=null">
                id,
            </if>
            <if test="empName!=null and empName!=''">
                emp_name,
            </if>
            <if test="empGender!=null and empGender!=''">
                emp_gender,
            </if>
            <if test="email!=null and email!=''">
                email,
            </if>
            <if test="birthday!=null">
                birthday,
            </if>
            <if test="updatetime!=null">
                updatetime,
            </if>
            <if test="createtime!=null">
                createtime,
            </if>
        </trim>
        <trim prefix="values(" suffix=")" suffixOverrides="," >
            <if test="id!=null">
                #{id},
            </if>
            <if test="empName!=null and empName!=''">
                #{empName},
            </if>
            <if test="empGender!=null and empGender!=''">
                #{empGender},
            </if>
            <if test="email!=null and email!=''">
                #{email},
            </if>
            <if test="birthday!=null">
                #{birthday},
            </if>
            <if test="updatetime!=null">
                #{updatetime},
            </if>
            <if test="createtime!=null">
                #{createtime},
            </if>
        </trim>
    </insert>

5、set if标签的使用

动态条件更新

int updateEmployeeSelective(Employee employee);

   <update id="updateEmployeeSelective">
        update employee
        <!--set中的的条件有一个成立,则自动加上set关键字,若所有条件不成立 则会报错: update employee where id=? 不成立-->
        <!--set会为最后一个成立的if去掉逗号 ,-->
        <set>
            <if test="empName!=null and empName!=''">
                emp_name=#{empName},
            </if>
            <if test="empGender!=null and empGender!=''">
                emp_gender=#{empGender},
            </if>
            <if test="email!=null and email!=''">
                email=#{email},
            </if>
            <if test="birthday!=null">
                birthday=#{birthday},
            </if>
            <if test="updatetime!=null">
                updatetime=#{updatetime},
            </if>
            <if test="createtime!=null">
                createtime=#{createtime},
            </if>
        </set>
        where id=#{id}
    </update>

6、foreach的使用

查询/删除多条数据(遍历数组)

这里的参数必须取别名

int deleteEmployeeMultiple(@Param("ids") Integer[] ids);

    <delete id="deleteEmployeeMultiple">
        delete from employee where id in
        <!--若数组为空则条件不成立会报错:delete from employee where id in-->
        <!--foreach遍历数组-->
        <!--collection:一般为被@param命名的集合别名-->
        <!--item:当前遍历的元素-->
        <!--open:当前sql开始的前缀-->
        <!--close:当前sql结束的后缀-->
        <!--separator:每个元素之间的分隔符-->
        <!--index:
                若为数组/List集合:则为当前索引
                若为map结合:则代表当前key
         -->
        <foreach collection="ids" item="id" open="(" close=")" separator="," >
            #{id}
        </foreach>
    </delete>
批量插入

这里的参数必须取别名

int addEmployeeList(@Param("list") List<Employee> list);

    <insert id="addEmployeeList">
        insert into employee(emp_name,emp_gender,email,birthday,updatetime,createtime) values
        <!--注意批量插入的格式为:insert into employee(emp_name,emp_gender,email,birthday,updatetime,createtime) values (?,?,?,?,?,?) , (?,?,?,?,?,?) , (?,?,?,?,?,?)-->
        <!--所以使用在foreach自动在没一次遍历加 ( 和 ) 需要手动加括号作为一次分段整体的添加-->
        <foreach collection="list" item="emp" separator=",">
            (#{emp.empName},#{emp.empGender},#{emp.email},#{emp.birthday},#{emp.updatetime},#{emp.createtime})
        </foreach>
    </insert>

7、chose when otherwise的使用

if-else查询

List<Employee> getEmployeeByWhen(Employee employee);

<select id="getEmployeeByWhen" resultType="org.lc.entity.Employee">
        select * from employee
        <where>
            <choose>
                <!--从上到下,只要满足一个when的条件,则后序条件都不执行-->
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="empName!=null and empName!=''">
                    emp_name=#{empName}
                </when>
                <when test="empGender!=null and empGender!=''">
                    emp_gender=#{empGender}
                </when>
                <!--若所有的when条件都不满足,则执行otherwise条件-->
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>

8、sql include标签的使用

抽取sql重用

避免使用select * from employee 会降低查询效率

    <sql id="BaseSql">id,emp_name,emp_gender,email,birthday,updatetime,createtime</sql> 
   
    <select id="getAllEmployee" resultType="org.lc.entity.Employee">
        select <include refid="BaseSql"/>
         from employee
    </select>

9、模糊查询

       <if test="empName!=null and empName!=''">
            and emp_name like concat('%',#{employee.name},'%')
        </if>

10、el常用判断表达式

在Mybatis中你的SQL语句中不能直接写大于或者小于等和xml标签冲突的特殊符号,需要进行转义:

&lt;<小于号
&gt;>大于号
&amp;&
&apos;'单引号
&quot;"双引号
&lt;&gt;<>不等于
&gt;=>=大于等于
&lt;=<=小于等于
create_date_time &gt;= #{startTime} and create_date_time &lt;= #{endTime}

或者直接使用 <![CDATA[ ]]> 将所有冲突的特殊符号放在其中

<if test="startTime != null ">
    AND <![CDATA[ order_date >= #{startTime,jdbcType=DATE}  ]]>
</if>
<if test="endTime != null ">
    AND order_date <![CDATA[ <= ]]> #{endTime,jdbcType=DATE} 
</if>

在动态sql中,例如where if标签中判断参数:

gt大于>
gte大于等于>=
eq是否等于==
neq不等于!=
lt小于< (在条件判断的时候,test不能包含 '<' 字符)
lte小于等于<= (在条件判断的时候,test不能包含 '<' 字符)

11、_parameter的使用

单个参数(基本数据类型/包装类型/String)

单个参数可以不用取别名

可以使用<if test="_parameter != null and _parameter!=''">,

  • <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="Java.lang.Integer" >
             select 
        <include refid="Base_Column_List" />
             from base.tb_user
        <if test="_parameter != null">
             where id = #{id,jdbcType=INTEGER}
        </if>
    </select>
    
多个参数

使用_parameter.get("0")获取第一个参数,_parameter.get("0").属性获取对象的属性值

List<User> select(User user,Page page)
<!--(通过parameter.get(0)得到第一个参数即user);-->
<if test='_parameter.get("0").name != null'>
  <!--通过0.name确保第一个参数user的name属性值-->
  name=#{0.name}  
</if>
判断map参数的键是否存在

_parameter.containsKey('键')

12、map作为参数取值

数据:

        Map<String, Object> map=new HashMap<>();
        List<String> list=new ArrayList<>();
        list.add("1189389726308478977");
        list.add("1189390295668469762");
        list.add("1189426437876985857");
        map.put("ids", list);
        map.put("firstId", "1189389726308478977");
        List<EduTeacher> list1 = mapper.test5(map);
        System.out.println(list1);
//可以不用为params取别名,因为可以直接通过键值取值
List<EduTeacher> test5(Map<String, Object> params);
  • 直接使用#{键}获取指定的键值

    •    <select id="test5" resultType="org.lc.domain.entity.EduTeacher" parameterType="map">
              select * from edu_teacher where id=#{firstId}
          </select>
      
  • 在foreach标签中collection="键" 获取键值

    •    <select id="test5" resultType="org.lc.domain.entity.EduTeacher" parameterType="map">
              select * from edu_teacher where id in
              <foreach collection="ids" separator="," open="(" close=")" item="id">
                  #{id}
              </foreach>
          </select>
      
    • 或者使用collection="_parameter['键']" 获取键值

      •     <select id="test5" resultType="org.lc.domain.entity.EduTeacher" parameterType="list">
                select * from edu_teacher where id in
                <foreach collection="_parameter['ids']" separator="," open="(" close=")" item="id">
                    #{id}
                </foreach>
            </select>
        
    • 使用_parameter['键']"取map中的list并判断list大小

      •                   <if test="_parameter['themeList']!=null and _parameter['themeList'].length>0">
                              and THEME_NO in
                              <foreach collection="_parameter['themeList']" open="(" close=")" item="themeNo" separator=",">
                                  #{themeNo}
                              </foreach>
                          </if>
        
        

14、if test

判断字符串和字符
  • 判断不为null

    <if test="name!=null">

  • 判断不为空串

    <if test="name!=null and name!=''">

    <if test="name!=null and !name.equals('')">

    <if test="name!=null and name.trim()!=''"> 去除空格后判断

  • 判断单个字符

    <if test="gender!=null and gender=='1'"> ❌不生效

    原因是:mybatis是用OGNL表达式来解析的,在OGNL的表达式中,'1'会被解析成字符,java是强类型的,char 和 一个string 会导致不等,所以if标签中的sql不会被解析。

    解决方法如下:

    <if test='gender!=null and gender=="1"'> 单引号中加双引号

    <if test="gender!=null and gender=='1'.toString()"> 使用toString()字符转为字符串

判断Integr

不能使用 startIndex!='' ,因为Integer类型永远不会和字符相等

<if test="startIndex!=null and startIndex==1">

⚠️ 注意:判断相等的时候必须用 == 即双等号,如果用单等号<if test="appClassId=-1">,则会导致参数appClassId变为赋值语句,即永远为-1

判断集合
  <if test='neIds!=null and neIds.size()!=0 and neIds.get(0)!="-1" and neIds.get(0)!=""'>

15、MyBatis Log插件使用生成样例

2021-12-02 18:29:35 [java.sql.PreparedStatement]-[DEBUG] ==>  Preparing: select * from .... 
2021-12-02 18:29:35 [java.sql.PreparedStatement]-[DEBUG] ==> Parameters: 2021-11-01 00:00:00(String) ...

四、缓存机制

MyBatis缓存机制:将缓存数据放在Map(HashMap)集合中;能保存查询一些数据

一级缓存:线程级别的缓存;本地缓存,SqlSession级别的缓存

二级缓存:全局范围的缓存,除过当前线程;SqSession能用外其它可以使用

1、一级缓存

SqlSession级别的缓存;默认存在

机制:只要之前查询过的数据,mybatis就会保存在一个缓存中(Map);下次获取直接从缓存中拿。

  • 只有在当前SqlSession内查询缓存才有效,关闭当前的SqlSession则缓存也清空
1)缓存失效的情况

①不同的SqlSession,使用不同的一级缓存

  • 只有同一个SqlSession期间查询到的数据会保存在这个SqlSession的缓存中
  • 下次使用这个SqlSession查询会从中拿(前提是之前的SqlSessin未关闭)

②同一个方法,不同的对象参数

  • 由于之前可能没查该对象,所以需要再查一遍

③在这个SqlSession期间只要在两次查询之间执行了任何一次增删改操作,缓存也会清空

④手动清空当前SqlSession的缓存

  • sqlSession.clearCache()
2)基本使用

①相同的SqlSession从缓存中查询

    @Test
    public void Test10(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
        EmployeeDao mapper1 = sqlSession1.getMapper(EmployeeDao.class);
        Employee Employee1 = mapper1.getEmployeeById(1);
        Employee Employee2 = mapper1.getEmployeeById(1);
        System.out.println(Employee1);
        System.out.println(Employee2);
        sqlSession1.close();
}

②不同的SqlSession缓存不同

    @Test
    public void Test10(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
        EmployeeDao mapper1 = sqlSession1.getMapper(EmployeeDao.class);
        Employee Employee1 = mapper1.getEmployeeById(1);
        System.out.println(Employee1);
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        EmployeeDao mapper2 = sqlSession2.getMapper(EmployeeDao.class);
        Employee Employee3 = mapper2.getEmployeeById(1);
        System.out.println(Employee3);
        sqlSession2.close();
    }

2、二级缓存

  • 当SqlSession关闭或者提交后,一级缓存的数据会放在二级缓存中
  • 使用二级缓存的对象必须实现序列化seralizable接口
1)配置流程

①需要手动开启二级缓存。在mybatis-cofig.xml配置

    <!--这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。-->
    <settings>
        <!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

②使某一个Dao.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.lc.dao.EmployeeDao">

    <cache></cache>
    
     <select id="getEmployeeById" resultType="Employee">
        select * from employee where id=#{id};
    </select>
    
</mapper>
2)基本使用

不同的SqlSession从二级缓存中拿数据

    @Test
    public void Test10(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
        EmployeeDao mapper1 = sqlSession1.getMapper(EmployeeDao.class);
        Employee Employee1 = mapper1.getEmployeeById(1);
        System.out.println(Employee1);
        //必须关闭或者提交才能放入二级缓存
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        EmployeeDao mapper2 = sqlSession2.getMapper(EmployeeDao.class);
        Employee Employee3 = mapper2.getEmployeeById(1);
        System.out.println(Employee3);
        sqlSession2.close();
    }

3、缓存查询顺序

先查二级缓存,再查一级缓存,最后查数据库

4、缓存相关属性

1)全局setting的cacheEnable:

  • 配置二级缓存的开关,一级缓存默认一直时打开的

2)select标签的useCache属性

  • 配置这个select是否使用二级缓存。一级缓存一直都是使用的

  •  <select id="getEmployeeById" resultType="Employee" useCache="false">
            select * from employee where id=#{id};
        </select>
    

3)sql标签的flushCache属性

  • 增删改默认flushCache=true,。sq执行后,会同时清空一级和二级缓存
  • 查询默认flushCache=false

4)sqlSesseion.clearCache()

  • 只是用来清除一级缓存

五、PageHelper分页

导包

    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.8</version>
    </dependency>

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>

    <!--配置mybatis分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
</configuration>

完整实例

自定义分页实体

@Getter
@Setter
public class ResponsePage {
    /**
     * 总页数
     */
    private Long total;
    /**
     * 查询的数据
     */
    private List<?> data;

    public static ResponsePage build(){
        return new ResponsePage();
    }
    public ResponsePage setTotal(Long total) {
        this.total = total;
        return this;
    }
    public ResponsePage setData(List<?> data) {
        this.data = data;
        return this;
    }
}

主要方法参数:

  • 获取查询结果

pageNum: 传入的页面

pageSize:每页的大小

PageHelper.startPage(int pageNum, int pageSize);

注意: 执行该分页代码后面必须紧跟查询方法,否则分页失效

  • 获取查询的详细参数

T: 查询的对象类型

list:查询到的对象集合

PageInfo<T> employeePageInfo=new PageInfo<>(List<T> list);

    @GetMapping("/getAll")
    public ResponsePage getAllEmployee(@RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "size", defaultValue = "10") Integer size) {
        //startPage(int pageNum, int pageSize)
        //参数: 页码,每页的大小
        PageHelper.startPage(page, size);
        //必须紧跟查询操作,否则分页无效
        List<Employee> allEmployee = employeeService.getAllEmployee();
        //将当前查询到的数据传入PageInfo中,得到详细参数
        PageInfo<Employee> employeePageInfo=new PageInfo<>(allEmployee);
        System.out.println("当前页码:"+employeePageInfo.getPageNum());
        System.out.println("总页码:"+employeePageInfo.getPages());
        System.out.println("总记录数:"+employeePageInfo.getTotal());
        System.out.println("当前页查询到的记录数:"+employeePageInfo.getSize());
        System.out.println("当前页大小:"+employeePageInfo.getPageSize());
        System.out.println("上一页:"+employeePageInfo.getPrePage());
        System.out.println("当前页查询的结果:"+employeePageInfo.getList());
        return new ResponsePage().setData(allEmployee).setTotal(employeePageInfo.getTotal());
    }

六、逆向工程

官网参考 http://mybatis.org/generator/configreference/xmlconfig.htmlopen in new window

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.4</version>
    </dependency>   
    <!--mybatis逆向工程-->
    <dependency>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-core</artifactId>
      <version>1.3.5</version>
    </dependency>

核心xml文件

mbg.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>

    <!--官网参考-->
    <!--http://mybatis.org/generator/configreference/xmlconfig.html-->

    <!--将该配置文件置于项目的根目录位置-->

    <!--targetRuntime: 生成sql的复杂度-->
    <!--targetRuntime:MyBatis3  标准的(多条件)-->
    <!--targetRuntime:MyBatis3Simple  简单的-->
    <!--targetRuntime:MyBatis3DynamicSql  动态sql-->
    <context id="default" targetRuntime="MyBatis3">

        <!--连接哪个数据库-->
        <!--指定数据库驱动,连接地址,用户名,密码-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/test"
                        userId="root"
                        password="123456">
        </jdbcConnection>

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

        <!--生成pojo-->
        <!--targetPackage:目标包   targetProject:目标项目 (.\src目标项目的src下 ) -->
        <javaModelGenerator targetPackage="org.mbg.eniity" targetProject=".\src\main\java\">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--sql映射文件位置,指定xml生成位置-->
        <!---->
        <sqlMapGenerator targetPackage="org.mbg.dao"  targetProject=".\src\main\resources\">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!--dao接口-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="org.mbg.dao"  targetProject=".\src\main\java\">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!--指定生成的表-->
        <!--tableName表名 -->
        <!--domainObjectName:表对应的对象名-->
        <table tableName="hr" domainObjectName="Hr"></table>
        <table tableName="hr_role" domainObjectName="HrRole"></table>
        <table tableName="role" domainObjectName="Role"></table>
    </context>
</generatorConfiguration>

生成执行代码

public class MyBatisGeneratorTest {
    public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定配置文件的路径
        File configFile = new File("mbg.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
}