一、MyBatis快速入门

  • MyBatis概述
    • MyBaits是一个半自动化的持久层框架
    • MyBatis封装了jdbc的很多细节,开发者只需要关注sql本身,无需关注注册驱动,获取连接等操作
    • MyBatis使用ORM思想来对结果集封装
  • ORM

    • 对象关系映射,是一种思想(类(表)—对象(一行数据)—属性(列))

      1、MyBatis相关配置文件

  • MyBatis核心配置文件是:SqlMapConfig.xml

    • 头约束
    • 配置数据库环境
      • 事务管理器
      • 数据库连接池
    • 加载映射文件,就是实体类的配置文件

      1. <?xml version="1.0" encoding="UTF-8" ?>
      2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
      3. <configuration>
      4. <!--配置数据库环境-->
      5. <environments default="mysql">
      6. <environment id="mysql">
      7. <!--事务管理器-->
      8. <transactionManager type="JDBC"></transactionManager>
      9. <!--使用默认的数据库的连接池-->
      10. <dataSource type="POOLED">
      11. <property name="driver" value="com.mysql.jdbc.Driver"></property>
      12. <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"></property>
      13. <property name="username" value="root"></property>
      14. <property name="password" value="root"></property>
      15. </dataSource>
      16. </environment>
      17. </environments>
      18. <!--加载映射文件-->
      19. <mappers>
      20. <mapper resource="com/smiledog/mapper/UserMapper.xml"></mapper>
      21. </mappers>
      22. </configuration>
  • 实体类的配置文件为:实体类名+Mapper.xml

    • 头约束
    • Sql语句
      1. <?xml version="1.0" encoding="UTF-8" ?>
      2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      3. <mapper namespace="UserMapper">
      4. <!--查询所有用户信息-->
      5. <select id="findAllUsers" resultType="com.itfxp.domain.User">
      6. select * from user
      7. </select>
      8. </mapper>
  • 测试代码

    • 加载核心配置文件
    • 构建sqlSessionFactor工厂对象
    • 通过工厂创建sqlSession会话对象
    • 执行sql语句

      1. public class MyBatisTest {
      2. public static void main(String[] args) throws IOException {
      3. // 加载核心配置文件
      4. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
      5. // 构建SqlSessionFactory工厂对象
      6. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
      7. // 通过工厂创建SqlSession会话对象
      8. SqlSession sqlSession = sessionFactory.openSession();
      9. // 执行sql语句
      10. List<User> list = sqlSession.selectList("UserMapper.findAllUsers");
      11. for (User user : list) {
      12. System.out.println(user);
      13. }
      14. // 释放资源
      15. sqlSession.close();
      16. is.close();
      17. }
      18. }

      2、MyBatis增删改查

      添加数据

      UserMapper配置文件

      1. <insert id="addUser" parameterType="com.smiledog.domain.User">
      2. insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
      3. </insert>

      测试代码

      1. private static void addUser() throws IOException {
      2. // 加载核心配置文件
      3. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
      4. // 构建SqlSessionFactory工厂对象
      5. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
      6. // 通过工厂创建SqlSession会话对象
      7. SqlSession sqlSession = sessionFactory.openSession();
      8. User user = new User();
      9. user.setUsername("王朝马汉");
      10. user.setBirthday(new Date());
      11. user.setSex("男");
      12. user.setAddress("河南开封");
      13. int insert = sqlSession.insert("user.addUser", user);
      14. System.out.println(insert);
      15. // 手动提交事务
      16. sqlSession.commit();
      17. // 释放资源
      18. sqlSession.close();
      19. is.close();
      20. }


      1、插入语句Insert标签
      2、在影射文件找那个使用parameterType属性指定插入数据类型
      3、sql语句#{实体属性名} 表示?占位符
      4、插入操作的API是sqlSession.instert(“命名空间.id”,实体对象);
      5、DML类型语句mybatis需要手动提交事务 sqlSession.commit( );

      修改数据

      UserMapper配置文件

      1. <update id="updateUser" parameterType="com.smiledog.domain.User">
      2. update user set username= #{username}, birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id}
      3. </update>

      测试代码

      1. private static void updateUser() throws IOException {
      2. // 加载核心配置文件
      3. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
      4. // 构建SqlSessionFactory工厂对象
      5. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
      6. // 通过工厂创建SqlSession会话对象
      7. SqlSession sqlSession = sessionFactory.openSession();
      8. User user = new User();
      9. user.setUsername("张三");
      10. user.setBirthday(new Date());
      11. user.setSex("男");
      12. user.setAddress("河南开封");
      13. user.setId(50);
      14. int update = sqlSession.update("user.updateUser", user);
      15. System.out.println(update);
      16. // 手动提交事务
      17. sqlSession.commit();
      18. // 释放资源
      19. sqlSession.close();
      20. is.close();
      21. }

      删除数据

      UserMapper配置文件

      1. <delete id="delUser" parameterType="int">
      2. delete from user where id = #{id}
      3. </delete>

      测试代码

      ```java private static void delUser() throws IOException { // 加载核心配置文件 InputStream is = Resources.getResourceAsStream(“SqlMapConfig.xml”);

      // 构建SqlSessionFactory工厂对象 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

      // 通过工厂创建SqlSession会话对象 SqlSession sqlSession = sessionFactory.openSession();

  1. int del = sqlSession.delete("user.delUser", 50);
  2. System.out.println(del);
  3. // 手动提交事务
  4. sqlSession.commit();
  5. // 释放资源
  6. sqlSession.close();
  7. is.close();

}

  1. <a name="0Mfm7"></a>
  2. ### 提取工具类
  3. ```java
  4. package com.yunhe.mybatis.utils;
  5. /*
  6. @ClassName SqlSessionFactoryUtil
  7. @Date 2021/6/23
  8. @Time 16:55
  9. */
  10. import org.apache.ibatis.io.Resources;
  11. import org.apache.ibatis.session.SqlSession;
  12. import org.apache.ibatis.session.SqlSessionFactory;
  13. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. public class SqlSessionFactoryUtil {
  17. public SqlSessionFactoryUtil() {
  18. }
  19. private static SqlSessionFactory sqlSessionFactory = null;
  20. static {
  21. try {
  22. //加载核心配置文件
  23. InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
  24. // 构建SqlSessionFactory工厂对象
  25. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. public static SqlSession openSession(){
  31. // 通过工厂创建SqlSession会话对象
  32. return sqlSessionFactory.openSession();
  33. }
  34. public static void close (SqlSession sqlSession){
  35. sqlSession.commit(); //提交事务
  36. sqlSession.close(); //释放资源
  37. }
  38. }

3、MyBatis常用标签

核心配置文件的层级关系:

  • Configuration

    • properties(属性)
    • setting(设置)
    • typeAliases(类型别名)
    • objectFactory(对象工厂)
    • plugis(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transationManager(事务管理器)
        • dataSource(数据源)
    • databaseldProvider(数据库厂商标识)
    • mappers(映射器)

      environments:

      数据库环境配置,支持多环境配置

      properties:

      加载外置的properties配置文件

      typeAliases:

      为Java类型设置一个短的名字(类型别名),mybatis框架内置了一些java类型的别名

      1. <typeAliases>
      2. <!--这种方式只能设置一个别名,如果有其他的,还得再写一个,这种方式不推荐-->
      3. <!--<typeAlias type="com.smiledog.domain.User" alias="User"></typeAlias>-->
      4. <!--将当前的包下的类名,都设置了别名,别名是:当前类的名字-->
      5. <package name="com.smiledog.domain"></package>
      6. </typeAliases>

      mappers:

      用于记载映射文件, ```java 基本使用方法:

加载指定接口的全限定名 ==注解开发时使用==

加载并扫描指定包下所有的接口 ==基于接口扫描方式加载==

  1. <a name="md0Lk"></a>
  2. ## 4、MyBatis的API
  3. <a name="0ZGQx"></a>
  4. #### Resource:
  5. 加载mybatis的核心配置文件
  6. ```java
  7. // 加载mybatis的核心配置文件,获取io流
  8. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  9. //也可以使用类加载器(ClassLoader)加载配置文件

SqlSessionFactoryBuilder:

根据mybatis的核心配置文件构建出SqlSessionFactory工厂对象

  1. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

SqlsessionFactory:

用于创建SqlSession会话对象(同Connection对象)
这是一个工厂对象,对于这种创建和销毁都非常消耗资源,一个项目中只需要存在一个即可

  1. // DML类型语句,需要手动提交事务
  2. SqlSession openSession();
  3. // 设置是否开启自动提交事务的会话对象,如果设置true,自动提交【了解】
  4. SqlSession openSession(boolean autoCommit);
  5. 一般不管这个,默认手动提交

SqlSession:

这是MyBatis的一个核心对象,我们基于这个对象可以实现对数据的CRUD操作
对于这个对象应做到每个线程多,每次用时打开,用完关闭

  1. - <T> T selectOne(String statement, Object parameter);
  2. - <E> List<E> selectList(String statement, Object parameter);
  3. - int insert(String statement, Object parameter);
  4. - int update(String statement, Object parameter);
  5. - int delete(String statement, Object parameter);
  6. - void commit();
  7. - void roolback();

二、MyBatis的实现

1、MyBatis实现Dao层

a、传统的Dao层实现方式

UserMapper接口:

  1. public interface UserMapper {
  2. // 查询所有
  3. public List<User> findAll();
  4. }

UserMapper实现类:

  1. public class UserMapperImpl implements UserMapper {
  2. @Override
  3. public List<User> findAll() {
  4. try {
  5. // 1.加载核心配置文件
  6. InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
  7. // 2.构建工厂
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
  9. // 3.创建会话
  10. SqlSession sqlSession = sqlSessionFactory.openSession();
  11. // 4.执行sql
  12. List<User> list = sqlSession.selectList("UserMapper.findAll");
  13. // 5.释放资源
  14. sqlSession.close();
  15. return list;
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. }
  19. return null;
  20. }
  21. }

Mapper映射文件:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="UserMapper">
  4. <!--查询所有-->
  5. <select id="findAll" resultType="User">
  6. select * from user
  7. </select>
  8. </mapper>

实现service的调用:

  1. public class UserMapperTest {
  2. // 模拟service
  3. public static void main(String[] args){
  4. // 调用dao层代码
  5. UserMapper userMapper = new UserMapperImpl();
  6. List<User> list = userMapper.findAll();
  7. System.out.println(list);
  8. }
  9. }

b、MyBatis接口代理模式

特别之处:
1、在MyBatis 的核心配置文件SqlMapConfig中配置Mappers

  1. <mappers>
  2. <!--动态获取,基于接口扫描进行加载mapper配置文件-->
  3. <!--路径为mapper配置文件所在包路径-->
  4. <package name="com.smiledog.mybatis.mapper"/>
  5. </mappers>

2、在使用中获取核心配置文件中获取接口实现类的代理对象,通过接口实现类对象调用方法

  1. public class MyBatisDaoTest {
  2. public static void main(String[] args) throws IOException {
  3. // 加载核心配置文件
  4. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  5. // 构建SqlSessionFactory工厂对象
  6. SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
  7. // 通过工厂创建SqlSession会话对象
  8. SqlSession sqlSession = sessionFactory.openSession();
  9. // 获取接口的实现类的代理对象
  10. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  11. List<User> allUser = mapper.findAllUser();
  12. for (User user : allUser) {
  13. System.out.println(user);
  14. }
  15. }
  16. }

c、MyBatis接口开发规范

  1. - Mapper映射文件的namespaceMapper接口全限定名一致
  2. - Mapper接口的方法名与id的属性名一致
  3. - 方法的参数类型与parameter属性类型一致
  4. - 方法的返回值类型与resultType属性类型一致
  5. - 映射文件需要与接口在同一个包下,文件名和接口名相同:扫描包,加载所有的映射文件:<package name = "com.smiledog.mapper" />

d、MyBatis增删改查

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.itfxp.mapper.UserMapper">
  4. <!--查询所有用户信息-->
  5. <select id="findAllUser" resultType="User">
  6. select * from user
  7. </select>
  8. <!--新增-->
  9. <insert id="save" parameterType="User">
  10. insert into user (username,birthday,sex,address)
  11. values(#{username},#{birthday},#{sex},#{address})
  12. </insert>
  13. <!--修改-->
  14. <update id="update" parameterType="User">
  15. update user set username = #{username},birthday = #{birthday},sex = #{sex},
  16. address = #{address} where id = #{id}
  17. </update>
  18. <!--删除-->
  19. <delete id="delete" parameterType="int">
  20. delete from user where id = #{id}
  21. </delete>
  22. <!--查询一个-->
  23. <select id="findById" parameterType="int" resultType="User">
  24. select * from user where id = #{id}
  25. </select>
  26. </mapper>

2、MyBatis单表查询

resultMap:

在查询数据时进行结果封装,会出现别名和实体类的属性名不一直跟的情况,导致赋值赋不上,这个时候我们就要使用resultMap属性,进行手动建立字段映射关系

  1. <!--
  2. resultMap 手动建立映射
  3. id="userResultMap"
  4. type="com.smiledog.domain.User" 建立映射的java类型
  5. id 标签 主键
  6. column="uid" 列名
  7. property="id" 实体属性名
  8. result 标签 普通字段
  9. column="name" 列名
  10. property="username" 实体属性名
  11. -->
  12. <resultMap id="userResultMap" type="com.smiledog.domain.User">
  13. <id column="uid" property="id"></id>
  14. <result column="name" property="username"></result>
  15. <result column="bir" property="birthday"></result>
  16. <result column="gender" property="sex"></result>
  17. <result column="address" property="address"></result>
  18. </resultMap>
  19. <!--查询所有用户信息-->
  20. <select id="findAllUser" resultMap="userResultMap">
  21. SELECT id AS uid, username AS `name`,birthday AS bir ,sex AS gender ,address FROM user
  22. </select>

模糊查询:

方式一:不建议使用

  1. <select id="findUserByLike1" parameterType="string" resultType="User">
  2. select * from user where username like #{username}
  3. </select>
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. // 创建工厂获取Session代码省略
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. List<User> users = mapper.findUserByLike1("%王%");
  8. for (User user : users) {
  9. System.out.println(user);
  10. }

方式二:mysql5.5版本以前不支持多单引号拼接
oracle数据库,除了别名位置,其余位置能使用双引号

  1. <select id="findUserByLike2" parameterType="string" resultType="User">
  2. select * from user where username like "%" #{username} "%"
  3. </select>
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. // 创建工厂获取Session代码省略
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. List<User> users = mapper.findUserByLike2("王");
  8. for (User user : users) {
  9. System.out.println(user);
  10. }

方式三:会出现sql注入
${}字符串拼接,如果接收到的简单数据类型,表达式名称必须是value

  1. <select id="findUserByLike3" parameterType="string" resultType="User">
  2. select * from user where username like '%${value}%'
  3. </select>
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. // 创建工厂获取Session代码省略
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. List<User> users = mapper.findUserByLike3("王");
  8. for (User user : users) {
  9. System.out.println(user);
  10. }

方式四:使用concat函数拼接

  1. <select id="findUserByLike4" parameterType="string" resultType="User">
  2. select * from user where username like concat(concat('%',#{username}),'%')
  3. </select>
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. // 创建工厂获取Session代码省略
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. List<User> users = mapper.findUserByLike4("王");
  8. for (User user : users) {
  9. System.out.println(user);
  10. }

#{}与${}的区别

${}:底层Statement

  1. - sql与拼接参数拼接在一起,会出现sql注入问题
  2. - 每次执行sql语句都会编译一次
  3. - 接收简单类型,命名:${value}
  4. - 接收引用类型,命名:${属性名}
  5. - 字符串类型需要加 '${value}'

#{}:底层PreparedStatement

  1. - sql与参数分离,不会出现sql注入问题
  2. - sql只需要编译一次
  3. - 接收简单类型,命名:#{随便写}
  4. - 接收引用类型,命名:#{属性名}

3、MyBatis映射文件

返回主键:

在插入数据时,我们有时候需要获取,插入的该条数据的主键

useGeneratedkeys属性

此方式只支持主键自增

  1. <insert id="addUser" parameterType="User"
  2. useGeneratedKeys="true"
  3. keyColumn="id"
  4. keyProperty="id">
  5. insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
  6. </insert>

selectKey标签

  1. <insert id="addUser" parameterType="User">
  2. <selectKey keyColumn="id" ==> 表中主键列
  3. keyProperty="id" ==> 实体主键属性
  4. resultType="int" ==> 实体类逐渐属性类型
  5. order="AFTER"> ==> 表示此这个标签的sql语句实在insert语句之前执行(BEFORE),还是之后执行(AFTER
  6. SELECT LAST_INSERT_ID()
  7. ==>该函数是mysql提供的一个高级查询的函数,主要用于获取最后一次插入数据时的id
  8. </selectKey>
  9. insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
  10. </insert>

动态SQL:

根据用户传入的参数不同,生成的sql语句结构也就不同,查询数据也不同,这就是动态SQL

if标签:

比如有两个参数:id和username

  1. <!--
  2. if标签 条件判断
  3. where标签 相当于 where 1=1 功能,如果没有条件情况下 where语句不在sql语句拼接
  4. 可以去掉第一个 and 或者 or
  5. -->
  6. <select id="findByIdAndUsernameIf" parameterType="User" resultType="User">
  7. select * from user
  8. <where>
  9. <if test="id != null">
  10. and id= #{id}
  11. </if>
  12. <if test="username !=null">
  13. or username = #{username}
  14. </if>
  15. </where>
  16. </select>

set标签:

主要用于update更新数据

  1. <!--
  2. set标签 更新 ,将条件中的最后一个逗号抹除
  3. -->
  4. <update id="updateIf" parameterType="User">
  5. update user
  6. <set>
  7. <if test="username !=null">
  8. username = #{username} ,
  9. </if>
  10. <if test="birthday !=null">
  11. birthday = #{birthday} ,
  12. </if>
  13. <if test="sex !=null">
  14. sex = #{sex} ,
  15. </if>
  16. <if test="address != null">
  17. address = #{address},
  18. </if>
  19. </set>
  20. where id = #{id}
  21. </update>

foreach标签:

相关属性:

  1. - collection:代表要遍历的集合元素
  2. - open:代表语句的开始部分
  3. - close:代表结束部分
  4. - item:代表遍历集合的每个元素,生成的变量名
  5. - sperator:代表分隔符
  1. 多个id查询数据
  2. <!--
  3. foreach标签,普通list集合
  4. 传递 普通类型list集合 collection="list"
  5. 属性取值:collectionlist
  6. -->
  7. <select id="findUsersForEacheList" parameterType="list" resultType="User">
  8. select * from user where id in
  9. <foreach collection="list" open="(" close=")" item="id" separator=",">
  10. #{id}
  11. </foreach>
  12. </select>
  13. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  14. <!--
  15. foreach标签,普通array数组
  16. 传统 普通类型array数组 collection="array"
  17. 属性取值 array
  18. -->
  19. <!--<select id="findUsersForEacheArray" parameterType="int" resultType="User">-->
  20. <select id="findUsersForEacheArray" parameterType="int[]" resultType="User">
  21. select * from user where id in
  22. <foreach collection="array" open="(" close=")" item="id" separator=",">
  23. #{id}
  24. </foreach>
  25. </select>

SQL片段:

映射文件中可以将重复的sql提取出来,使用时用include引用即可

  1. <!--
  2. 将当前映射文件的共同的sql代码抽取一个片段,实现sql的复用性...
  3. id="selectUser" 当前sql片段的唯一标识
  4. -->
  5. <sql id="selectUser">
  6. select id,username,birthday,sex,address from user
  7. </sql>
  8. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  9. <select id="findUsersByIds" parameterType="User" resultType="User">
  10. <include refid="selectUser" /> where id in
  11. <foreach collection="ids" open="(" close=")" item="id" separator=",">
  12. #{id}
  13. </foreach>
  14. </select>

三、多表查询