Mybatis的基本使用

1. Mybatis的基本使用

1. 前提条件

mybatis操作数据库需要一个实体类和数据库表字段一一对应。

2. 导入依赖

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
    </dependency>
</dependencies>

3. 创建数据库表和实体类

  • 创建数据库表

    CREATE TABLE `user` (
        `id` int(11) NOT NULL auto_increment,
        `username` varchar(32) NOT NULL COMMENT '用户名称',
        `birthday` datetime default NULL COMMENT '生日',
        `sex` char(1) default NULL COMMENT '性别',
        `address` varchar(256) default NULL COMMENT '地址',
        PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  • 创建对应的实体类

    • 使用lombok工具
    import lombok.Builder;
    import lombok.Data;
    import java.util.Date;
    
    @Builder
    public class User {
    
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        public User() {
        }
    
        public User(Integer id, String username, Date birthday, String sex, String address) {
            this.id = id;
            this.username = username;
            this.birthday = birthday;
            this.sex = sex;
            this.address = address;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }
    
    

4. dao层接口和编写sql语句的xml文件

  1. dao接口
import java.io.Serializable;
import java.util.List;

public interface UserDao<T> extends Serializable {

    /**
     * 查询所有
     * @return 符合条件的list集合
     */
    public List<T> selectAll();

}
  1. 对象的接口的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="com.kl.dao.UserDao">
    
        <!--
        xml配置文件中的关键字说明
        namespace: 名称空间,表示该配置文件操作那个dao接口
        id:        dao接口中对应的方法名
        resultType: 返回的结果封装为什么类型
         -->
    
        <!-- 查询所有 -->
        <select id="selectAll" resultType="com.kl.bean.User">
            select id,username,birthday,sex,address
            from user
        </select>
    </mapper>
    

5. Mybatis的配置文件(SqlMapConfig.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">
<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.0.113:3306/mybatis?characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <mapper resource="com/kl/dao/userDao.xml"/>
    </mappers>

</configuration>

6. 单元测试

import com.kl.bean.User;
import com.kl.dao.UserDao;
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.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class MybatisTest {
    
    public static InputStream in = null;
    public static SqlSessionFactoryBuilder builder = null;
    public static SqlSession session = null;

    /**
     * 测试开始时执行
     */
    @Before
    public void beforeTest() throws IOException {
        System.out.println("测试开始...");
        // 1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.创建SqlSessionFactory工厂
        builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        // 3.使用工厂生产SqlSession对象
        session = factory.openSession();
    }

    /**
     * 测试最后执行的方法
     */
    @After
    public void afterTest() throws IOException {
        // 提交事务
        session.commit();
        // 释放资源
        session.close();
        in.close();
        System.out.println("测试结束...");
    }

    /**
     * 测试查询所有
     */
    @Test
    public void selectAllTest(){
        // 使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        // 使用代理对象执行方法
        List<User> users = userDao.selectAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

2. Mybatis的CRUD

1. dao层接口

import com.kl.bean.User;
import java.io.Serializable;
import java.util.List;

/**
 * 用户持久层接口
 */
public interface UserDao<T> extends Serializable {

    /**
     * 添加
     * @param t 添加的数据类型
     * @return  影响的行数
     */
    public int insert(T t);

    /**
     * 根据id删除数据
     * @param id 删除数据对应的id
     * @return   影响的行数
     */
    public int deleteById(int id);

    /**
     * 根据传入的id集合进行批量删除
     * @param ids id集合
     * @return    返回删除的记录条数
     */
    public int deleteBatchById(List<Integer> list);

    /**
     * 根据id更新
     * @param t     需要对象
     * @return      更新的行数
     */
    public int updateById(T t);

    /**
     * 根据id查询
     * @param id 查询的数据对应的id
     * @return   符合条件的对象
     */
    public <T> T selectById(int id);

    /**
     * 模糊查询
     * @return 符合条件的list集合
     */
    public List<T> selectByLikeByIf(User user);

    /**
     * 条件查询使用if标签
     * @param user 传入查询对象
     * @return     符合条件的list集合
     */
    public List<T> selectByCondition(User user);

    /**
     * 条件查询使用if标签和where标签
     * @param user 传入查询对象
     * @return     符合条件的list集合
     */
    public List<T> selectByLikeByIfAndWhere(User user);

    /**
     * 查询所有
     * @return list集合
     */
    public List<T> selectAll();

    /**
     * count() 聚合函数的使用
     * @return list集合
     */
    public int count();
}

2. 对应的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="com.kl.dao.UserDao">

    <!--
    xml配置文件中的关键字说明
    namespace       :名称空间,表示该配置文件操作那个dao接口,全限定类名
    id              :dao接口中对应的方法名,全限定类名
    parameterType   : 传入参数的类型,写参数的全限定类名
    resultType      : 返回的结果封装的类型,全限定类名
    #{}             : 用于接收传递进来的参数
    -->

    <!-- 基础的查询字段封装 -->
    <sql id="baseSelectSql">
        select id, username, birthday, sex, address
    </sql>

    <!-- 添加 -->
    <insert id="insert" parameterType="com.kl.bean.User">
        <!--
        配置数据主键自动增长情况下添加数据成功后返回的主键:selectKey标签
        keyProperty:对应实体类的key
        keyColumn  :对应数据库表的key
        resultType :返回的类型
        order      :什么时候返回 AFTER:执行了添加操作之后,BEFORE:执行添加操作之前
         -->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert
        into user(username,birthday,sex,address)
        values(#{username},#{birthday},#{sex},#{address})
    </insert>

    <!-- 根据id删除 -->
    <delete id="deleteById" parameterType="int">
        delete
        from user
        where id = #{id}
    </delete>

    <!--
    根据传入的id集合进行批量删除
    foreach :
            collection  :代表要遍历的集合元素,注意编写时不要写#{}
            open        :代表语句的开始部分
            close       :代表结束部分
            item        :代表遍历集合的每个元素,生成的变量名
            separator   :代表分隔符
     注意:parameterType中如果传递的参数名字为list或者其他的集合
           则在使用到list集合的地方必须要使用list变量名,不然mybatis无法识别
     -->
    <delete id="deleteBatchById" parameterType="list">
        delete
        from user
        <where>
           <if test="list != null and list.size() > 0">
               <foreach collection="list" open="and id in (" close=")" item="id" separator=",">
                    #{id}
               </foreach>
           </if>
        </where>
    </delete>

    <!-- 根据id修改 -->
    <update id="updateById" parameterType="com.kl.bean.User">
        update user
        set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address}
        where id = #{id}
    </update>

    <!-- 根据id查询 -->
    <select id="selectById" parameterType="int" resultType="com.kl.bean.User">
        <include refid="baseSelectSql"/>
        from user
        where id = #{id}
    </select>

    <!-- 条件查询使用if标签 -->
    <select id="selectByLikeByIf" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
        <include refid="baseSelectSql"/>
        from user
        where 1 = 1
        <if test="username != null and username != '' ">
            and username like #{username}
        </if>
        <if test="birthday != null and birthday != '' ">
            and birthday like #{birthday}
        </if>
        <if test="sex != null and sex != '' ">
            and sex like #{sex}
        </if>
        <if test="address != null and address != '' ">
            and address like #{address}
        </if>
    </select>

    <!-- 条件查询使用if标签和where标签 -->
    <select id="selectByLikeByIfAndWhere" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
        <include refid="baseSelectSql"/>
        from user
        <where>
            <if test="username != null and username != '' ">
                and username like #{username}
            </if>
            <if test="birthday != null and birthday != '' ">
                and birthday like #{birthday}
            </if>
            <if test="sex != null and sex != '' ">
                and sex like #{sex}
            </if>
            <if test="address != null and address != '' ">
                and address like #{address}
            </if>
        </where>
    </select>

    <!-- 条件分页查询 -->
    <select id="selectByCondition" resultType="com.kl.bean.User">
        <include refid="baseSelectSql"/>
        from user
        <where>
            <if test="username != null and username != '' ">
                and username like #{username}
            </if>
            <if test="birthday != null and birthday != '' ">
                and birthday like #{birthday}
            </if>
            <if test="sex != null and sex != '' ">
                and sex like #{sex}
            </if>
            <if test="address != null and address != '' ">
                and address like #{address}
            </if>
        </where>
        limit 0,5
    </select>

    <!-- 查询所有 -->
    <select id="selectAll" resultType="com.kl.bean.User">
        <include refid="baseSelectSql"/>
        from user
    </select>

    <!-- count() 聚合函数的使用 -->
    <select id="count" resultType="int">
        select count(*)
        from user;
    </select>

</mapper>

3. 单元测试类

import com.kl.bean.User;
import com.kl.dao.UserDao;
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.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 测试mybatis
 */
public class MybatisTest {

    public static InputStream in = null;

    public static SqlSessionFactoryBuilder builder = null;

    public static SqlSession session = null;

    /**
     * 测试开始时执行
     */
    @Before
    public void beforeTest() throws IOException {
        System.out.println("测试开始...");
        // 1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.创建SqlSessionFactory工厂
        builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        // 3.使用工厂生产SqlSession对象
        session = factory.openSession();
    }

    /**
     * 测试最后执行的方法
     */
    @After
    public void afterTest() throws IOException {

        // 提交事务
        session.commit();
        // 释放资源
        session.close();
        in.close();
        System.out.println("测试结束...");
    }

    /**
     * 添加
     */
    @Test
    public void insertTest(){
        // 使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);

        // 创建一个User对象,用于添加操作
        User user = User.builder()
                .username("名字")
                .birthday(new Date())
                .sex("男")
                .address("地址")
                .build();

        System.out.println("添加前...");
        System.out.println(user);
        int count = userDao.insert(user);
        System.out.println(count);
        System.out.println("添加后...");
        System.out.println(user);
    }

    /**
     * 根据id删除数据
     */
    @Test
    public void deleteByIdTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        int count = userDao.deleteById(53);
        System.out.println(count);
    }

    /**
     * 根据id删除数据
     */
    @Test
    public void deleteBatchByIdTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        List<Integer> list = new ArrayList<Integer>();

        list.add(67);
        list.add(68);
        list.add(69);
        list.add(70);
        int count = userDao.deleteBatchById(list);
        System.out.println(count);
    }

    /**
     * 根据id更新
     */
    @Test
    public void updateByIdTest(){
        UserDao userDao = session.getMapper(UserDao.class);

        User user = User
                .builder()
                .id(53)
                .username("测试修改")
                .birthday(new Date())
                .sex("男")
                .address("地址")
                .build();
        int count = userDao.updateById(user);
        System.out.println(count);
    }

    /**
     * 根据id查询
     */
    @Test
    public void selectByIdTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        User user = (User) userDao.selectById(41);
        System.out.println(user);
    }

    /**
     * 根据id查询
     */
    @Test
    public void selectByLikeByIfTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        User userVo = User
                .builder()
                .username("%小%")
                .address("%金%")
                .build();
        List<User> users = userDao.selectByLikeByIf(userVo);
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 条件查询使用if标签和where标签
     */
    @Test
    public void selectByLikeByIfAndWhereTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        User userVo = User
                .builder()
                .username("%小%")
                .address("%金%")
                .build();
        List<User> users = userDao.selectByLikeByIfAndWhere(userVo);
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 条件查询使用if标签和where标签
     */
    @Test
    public void selectByConditionTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        User userVo = new User();
        List<User> users = userDao.selectByCondition(userVo);
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试查询所有
     */
    @Test
    public void selectAllTest(){
        // 使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        // 使用代理对象执行方法
        List<User> users = userDao.selectAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * count() 聚合函数的使用
     */
    @Test
    public void countTest(){
        // 使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        // 使用代理对象执行方法
        int count = userDao.count();
        System.out.println(count);
    }
}

3. #{ }与${ }的区别

  1. { }表示一个占位符号

    通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,

    #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类

    型值,#{}括号中可以是 value 或其它名称。

  2. ${}表示拼接 sql 串

    通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简

    单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

4. 动态SQL标签

1. if 标签

  • 基本概念:当在where条件后面跟的字段不确定是否存着时,可以使用if标签,当字段存入的字段不为null时才拼接到查询条件的后面。否则不拼接。

1. dao层代码

/**
 * 模糊查询
 * @return 符合条件的list集合
 */
public List<T> selectByLike(User user);

2. xml映射配置文件

<!-- 模糊查询 -->
<select id="selectByLike" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
    select id,username,birthday,sex,address
    from user
    where 1 = 1
    <if test="username != null and username != '' ">
        and username like #{username}
    </if>
    <if test="birthday != null and birthday != '' ">
        and birthday like #{birthday}
    </if>
    <if test="sex != null and sex != '' ">
        and sex like #{sex}
    </if>
    <if test="address != null and address != '' ">
        and address like #{address}
    </if>
</select>

3. 单元测试

/**
 * 根据id查询
 */
@Test
public void selectByLikeTest(){
    UserDao userDao = session.getMapper(UserDao.class);
    User userVo = User
        .builder()
        .username("%小%")
        .address("%金%")
        .build();
    List<User> users = userDao.selectByLike(userVo);
    for (User user : users) {
        System.out.println(user);
    }
}

2. where标签

  • 目的:为了简化 where 1=1 的条件拼装,我们可以采用 where 标签来简化开发

1. dao层接口

/**
 * 条件查询使用if标签和where标签
 * @param user 传入查询对象
 * @return     符合条件的list集合
 */
public List<T> selectByLikeByIfAndWhere(User user);

2. xml映射配置文件

<!-- 条件查询使用if标签和where标签 -->
<select id="selectByLikeByIfAndWhere" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
    select id,username,birthday,sex,address
    from user
    <where>
        <if test="username != null and username != '' ">
            and username like #{username}
        </if>
        <if test="birthday != null and birthday != '' ">
            and birthday like #{birthday}
        </if>
        <if test="sex != null and sex != '' ">
            and sex like #{sex}
        </if>
        <if test="address != null and address != '' ">
            and address like #{address}
        </if>
    </where>
</select>

3. 单元测试

/**
 * 条件查询使用if标签和where标签
 */
@Test
public void selectByLikeByIfAndWhereTest(){
    UserDao userDao = session.getMapper(UserDao.class);
    User userVo = User
        .builder()
        .username("%小%")
        .address("%金%")
        .build();
    List<User> users = userDao.selectByLikeByIfAndWhere(userVo);
    for (User user : users) {
        System.out.println(user);
    }
}

3. foreach 标签

  • 作用:用于解析传入进来的集合参数
  • 使用foreach 遍历传入的list集合,根据得到的id进行数据删除

1. dao层接口

/**
 * 根据传入的id集合进行批量删除
 * @param ids id集合
 * @return    返回删除的记录条数
 */
public int deleteBatchById(List<Integer> list);

2. xml映射配置文件

<!--
    根据传入的id集合进行批量删除
    foreach :
            collection  :代表要遍历的集合元素,注意编写时不要写#{}
            open        :代表语句的开始部分
            close       :代表结束部分
            item        :代表遍历集合的每个元素,生成的变量名
            separator   :代表分隔符
     注意:parameterType中如果传递的参数名字为list或者其他的集合
           则在使用到list集合的地方必须要使用list变量名,不然mybatis无法识别
-->
<delete id="deleteBatchById" parameterType="list">
    delete
    from user
    <where>
        <if test="list != null and list.size() > 0">
            <foreach collection="list" open="and id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </if>
    </where>
</delete>

3. 单元测试

/**
 * 根据id删除数据
 */
@Test
public void deleteBatchByIdTest(){
    UserDao userDao = session.getMapper(UserDao.class);
    List<Integer> list = new ArrayList<Integer>();

    list.add(67);
    list.add(68);
    list.add(69);
    list.add(70);
    int count = userDao.deleteBatchById(list);
    System.out.println(count);
}

5. Mybatis中的sql片段简化

  • 当重复的sql出现的次数过多时,可以重复的sql语句进行抽取出来,使用是再使用include标签进行引入即可。
  • 例如:
    • 将需要查询的字段进行封装

1. xml映射配置文件

<!-- 基础的查询字段封装 -->
<sql id="baseSelectSql">
    select id, username, birthday, sex, address
</sql>

<!-- 使用基础的查询字段封装 -->
<!-- 查询所有 -->
<select id="selectAll" resultType="com.kl.bean.User">
    <include refid="baseSelectSql"/>
    from user
</select>

6. 聚合函数的使用

1. count() 函数

  • 作用:统计查询到数据的数量,
    • count(*):统计所有的包括null
    • count(具体字段):统计的次数不包括null

1. dao层接口

/**
 * count() 聚合函数的使用
 * @return list集合
 */
public int count();

2. xml映射配置文件

<!-- count() 聚合函数的使用 -->
<select id="count" resultType="int">
    select count(*)
    from user;
</select>

4. 单元测试

/**
 * count() 聚合函数的使用
 */
@Test
public void countTest(){
    // 使用SqlSession创建Dao接口的代理对象
    UserDao userDao = session.getMapper(UserDao.class);
    // 使用代理对象执行方法
    int count = userDao.count();
    System.out.println(count);
}
posted on 2021-08-15 22:52  秃头靓仔-001  阅读(75)  评论(0编辑  收藏  举报