mybatis

MyBatis

一、概念

​ MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

二、安装

1) mybatis依赖

​ 要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可

​ 如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

2)在idea中设置mybatis配置文件

​ mybatis-config.xm和mybatis-mapper.xml的l文件(包含了对 MyBatis 系统的核心设置)

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>
    <typeAliases>
        <package name=""/>
    </typeAliases>

    <environments default="">
        <environment id="">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value=""/>
                <property name="url" value=""/>
                <property name="username" value=""/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
    </mappers>
</configuration>

mybatis-mapper.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="">
    
</mapper>

3)配置文件属性的描述

mybatis-config.xml文件内容描述

mybatis-config.xml存放在 resources目录下

<?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>
    <!-- typeAliases用于配置实体类的别名 -->
    <typeAliases>
        <!-- 方式一:为每一个实例类分别指定一个别名,使用时不区分大小写 -->
        <!-- <typeAlias type="end.nf.mybatis.entity.User" alias="user"/> -->

        <!-- 方式二:直接指定实体类的包,这样mybatis就会自动给这个包下的所有的实体类自动创建别名,别名就是类名(不包括包名),并且使用时也不区分大小写 -->
        <package name="edu.nf.mybatis.entity"/>
    </typeAliases>
    <!-- environments(配置环境):主要是是配置不同数据库的数据源 ,default指定使用的默认数据源环境的id-->
    <environments default="mysql">
        <!-- environment:配置MySQL数据源的环境,id通常指定数据库的名 -->
        <environment id="mysql">
            <!-- transactionManager:事务管理使用JDBC的事务 -->
            <transactionManager type="JDBC"/>
            <!-- type指定为pool表示数据源连接使用连接池 -->
            <!-- 目前是可以复用的 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/pms?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;timeZone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="wyy"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 可以配置多个MySQL数据源 -->

    <!-- mappers:指定映射配置文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>


mybatis-mapper.xml文件内容描述

小乌鸦的插件:MyBatisX

<?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)创建名称,并且放入resources下的子mappers文件夹中 -->
<!-- namespace:指定Dao接口的完整类名 -->
<mapper namespace="edu.nf.mybatis.dao.UserDao">
    <!-- 给UserDao接口中的所有方法编写相应的SQL语句 -->
    <!-- insert表示插入语句,对应的删除和修改就是update和delete标签 -->
    <!-- id:指定的方法名,用于绑定SQL语句 -->
    <!-- parameterType:指定参数的类型(edu.nf.mybatis.entity.User),可以引用别名 -->
    <!-- 在<insert>标签中,不能编写任何注释,只能编写sql语句 -->
    <!-- sql语句中的参数使用#{实体的属性名}来获取实体对象中属性的值 -->	    
  	<!-- parameterType:对应的事dao接口的参数类型
         实体类参数:使用完整类名或实体别名
         map参数:map
         list或array参数:collection
         基本数据类型参数:int、float、long...
         字符串参数:string-->
  	    <!-- parameterType:对应的事dao接口的参数类型
         实体类参数:使用完整类名或实体别名
         map参数:map
         list或array参数:collection
         基本数据类型参数:int、float、long...
         字符串参数:string-->
    <insert id="save" parameterType="user">
        insert into user(uname,age) values(#{uname},#{age});
    </insert>

    <!-- 如果参数是map,那么ognl表达式的值为map的key -->
    <insert id="save2" parameterType="map">
        insert into user(uname,age) values(#{uname},#{age});
    </insert>

    <update id="update" parameterType="user">
        update user set uname = #{uname} where uid = #{uid};
    </update>

    <!-- 删除 -->
    <!-- 注意:当前方法参数只有一个并且是一个普通类型的时候,那么ognl的值可以任意填写 -->
    <delete id="delete" parameterType="int">
        delete from user where uid = #{id};
    </delete>
</mapper>

三、使用mybatis

1)创建MyBatisUtil工具类

注意:手动提交事物与自动提交事物的区别

​ 手动提交事务:执行多条SQL语句时 - 比如:转账、批量增删改查等操作

​ 自动提交事物:只执行一条SQL语句

public class MyBatisUtils {
    /**
     * 声明SqlSessionFactory,用于创建SqlSession实体
     */
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 在静态代码块中初始化SqlSessionFactory工厂
     */
    static {
        // 1.通过查询MyBatis的核心文件,先创建一个用于读取xml的文件输入流
        try {
            InputStream is = Resources.getResourceAsStream("mybatis.xml");

            // 2.将输入流传给创建的SqlSessionFactoryBuilder进行解析,并初始化
            // 整个SqlSessionFactory工厂对象
            sqlSessionFactory  = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            throw new RuntimeException("Init mybatis error." , e);
        }
    }

    /**
     * SqlSession是操作数据库的核心对象,相当于封装了整个Connection
     * 不带参数的openSession方法的到的SqlSession是需要我们手动提交事物的
     * 手动提交事物:执行多个sql - 比如:转账、批量增删改查
     * @return
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * openSession方法还可以传入一个boolean类的的参数
     * 如果设置为true,创建出来的SqlSession就会自动提交事务
     * 反之,false一样是受同行提交事物
     * 自动提交事物:执行1个sql
     * @param autoCommit 是否自动提交
     * @return
     */
    public static SqlSession getSqlSession(Boolean autoCommit){
        return sqlSessionFactory.openSession(autoCommit);
    }
}

2)编写实体类、Dao等

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer uid;

    private String uname;

    private Integer age;
}
	

public interface UserDao {
    /**
     * 添加用户
     * @param user
     */
    void save(User user);
  
  	/**
     * 添加用户
     * @param map
     */
  	void save2(Map<String ,Object> map);
}

3)实现类

public class UserDaoImpl implements UserDao {
    @Override
    public void save(User user) {
        // 先创建SqlSession - 放在try中,就不需要我们手动去关闭SqlSession资源
        SqlSession session = MyBatisUtils.getSqlSession();
        try {
            // 执行保存操作
            // getMapper:获取接口的class,调用这个方法
            session.getMapper(UserDao.class).save(user);
			
            // 手动提交事务
            session.commit();
        } catch (RuntimeException e) {
            e.printStackTrace();
            // 事务的回滚:手动提交事务的时候需要事务回滚
            session.rollback();
        } finally {
            session.close();
        }
    }
  
   @Override
    public void save2(Map<String, Object> map) {
        SqlSession session = MyBatisUtils.getSqlSession(true);
        try {
            session.getMapper(UserDao.class).save2(map);
        } catch(RuntimeException e){
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

4)映射配置文件

注意:映射配置文件:通常以(类名+Mapper)创建名称,并且放入resources下的子mappers文件夹中

四、UUID和雪花ID

一、UUID

1、生成UUID

public class UUIDUtils {
    public static String createUUID(){
        String uuid = UUID.randomUUID().toString();
        // 去除UUID的“-” :把“-”改为null字符
        return  uuid.replace("-","");
    }

    public static void main(String[] args) {
        System.out.println(createUUID());
    }
}

2、在mybatis中使用UUID

<?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="edu.nf.ch02.dao.StudentDao">
    <!-- 使用UUID作为主键
        方式一:使用Java的UUID工具类来生成uuid插入数据库 - (推荐)
        方式二:基于不同数据库的uuid生成函数来创建uuid,
        例如MySQL的生成函数是uuid(),因此在执行sql前可以利用此函数生成一个uuid -->
    <!-- selectKey的keyProperty指定通过uuid()函数乘车的id先保存到实体的stuId字段中
        resultType:返回的字段类型
        order设置为before表示为在执行insert语句之前先执行select uuid(),然后在执行insert语句,此时的insert语句中的stuId是已经存在值的了 -->
    <insert id="saveStu" parameterType="student">
        <selectKey keyProperty="stuId" resultType="string" order="BEFORE">
            select uuid();
        </selectKey>
        insert into stu_info(stu_id, stu_name) values (#{stuId}, #{stuName});
    </insert>

    <!-- 当数据量非常大的时候会进行分库分表,
         此时自增的id回来来业务上的问题(不同的表会产生相同的id值),
         因此可以考虑采用雪花ID,生成雪花ID可以使用开源的工具类生成(例如:hutool)
         雪花ID是一个长度为64的long类型的id-->
</mapper>

二、雪花ID

1、概念

世界上,没有完全相同的两片雪花。这就是雪花算法这个名称的由来。雪花算法(SnowFlake)是Twitter公司发明的一种算法,主要目的是解决在分布式环境下,ID怎样生成的问题。

img

在正常的业务开发中,数据库中的主键或者唯一键,都需要生成一个唯一标识,如用户id、订单id、订单编号等。

那么雪花算法是如何保证在高并发的情况下,能够保证不重复呢?

雪花ID的组成

在Java中表示雪花算法生成的id,需要使用Long类型,雪花算法是由1位符号位,0表示正数,1表示负数,id一般都是正数。

接下来的41位为一个毫秒级时间戳,这个时间戳存储的并不是当前时间,而是当前时间戳与指定的时间戳之间的差值,即指定时间戳 - 当前时间戳。

10位的数据机器位,可以表示2的10次方,即1024个节点,其中包括五位数据中心id和五位工作节点id。

12位毫秒内的计数器,支持统一机器同一时间戳产生4096个id序号。

以上数据合在一起刚好64位,即一个Long型数据。

img

2、使用雪花ID
1、添加hutool依赖方便我们调用API方法
 <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>
2、生成雪花ID
public class SnowFlakeUtils {
    public static long create(){
        return IdUtil.getSnowflakeNextId();
    }

    public static void main(String[] args) {
        System.out.println(create());
        System.out.println(create());
        System.out.println(create());
    }
}
3、在mybatis中使用雪花ID
<?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">
<!-- namespace指定Dao的完整类名 -->
<mapper namespace="edu.nf.ch02.dao.UserDao">

    <!-- useGeneratedKeys设置为true表示要获取自增长的key,
         并通过keyProperty将取出来的id保存到实体的uid字段中 -->
    <insert id="saveUser" parameterType="user" useGeneratedKeys="true"
            keyProperty="uid">
        insert into user_info(u_name, u_tel) values(#{userName}, #{tel})
    </insert>

    <!-- 使用UUID作为主键 -->

</mapper>

五、多参数查询

多条件参数查询, 不需要指定parameterType

使用方法:

   	1. 当有多个参数时,ognl表达式中只能使用下标(例如:param1,param2)来绑定参数
   	2. 使用@Param注解来绑定 - 常用
<?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="edu.nf.ch03.dao.UserDao">

    <!-- resultType指定结果集返回映射的数据类型,
         注意:查询语句中使用“as 别名”来映射到实体类-->

    <!--也可以使用mybatis提供的驼峰命名,需要再mybatis核心配置文件启用,
        这样当实体类字段是规范的驼峰命名法,mybatis就会自动将查询的字段转换为驼峰映射-->
    <select id="getUserById" parameterType="int" resultType="user">
        select user_id, user_name, user_tel from user_info where user_id = #{uid}
    </select>

    <select id="getUserById2" parameterType="int" resultType="map">
        select user_id,user_name,user_tel from user_info where user_id = #{uid}
    </select>

    <!-- 查询用户列表 -->
    <select id="listUsers" resultType="user">
        select user_id, user_name, user_tel from user_info
    </select>

    <!-- 统计查询 -->
    <select id="countUser" resultType="int">
        select count(*) from user_info
    </select>

    <!-- 多条件参数查询, 不需要指定parameterType,因为parameterType只能指定一个参数的
         当有多个参数时,ognl表达式中只能使用下标(例如:param1,param2)来绑定参数
         或者使用@Param注解来绑定-->
    <select id="getUserById3" resultType="user">
        select user_id, user_name, user_tel from user_info
        where user_name = #{uname} and user_tel = #{tel}
    </select>


    <!-- 声明resultMap用于User实体类和user_info的表映射-->
    <resultMap id="userMap" type="user">
        <!-- id用于映射主键,property指定实体的字段名,column指定表列的名称 -->
        <id property="userId" column="user_id"/>
        <!-- 其他属性使用result标签来映射-->
        <result property="userName" column="user_name"/>
        <result property="userTel" column="user_tel"/>
    </resultMap>

    <!-- 使用resultMap映射查询结果集,对应上面id的值 -->
    <select id="listUsers2" resultMap="userMap">
        select user_id, user_name, user_tel from user_info
    </select>
</mapper>

使用注解

public interface UserDao {
  
    /**
     * 多条件查询
     * @param name
     * @param age
     * @return
     */
    User getUserById3(@Param("name") String name, @Param("age") int age);
}

驼峰命名法

<?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>
    <!-- 启用驼峰命名,将数据库字段的下划线转驼峰模式
         例如:user_name 自动转换为 userName -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <typeAliases>
        <!-- 实体的别名 -->
        <package name="edu.nf.ch03.entity"/>
    </typeAliases>

    <!-- 数据源环境配置 -->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/pms?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;timeZone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="wyy"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 映射配置文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

六、多表查询

1、多对一 and 多对多

多对一(查询一个对象):使用resultMap实现关联映射的是

多对多(查询一个集合):使用resultMap实现关联映射的是

<?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="edu.nf.ch04.dao.StuDao">
    <!-- 使用resultMap实现关联映射 -->
    <resultMap id="stuMap" type="edu.nf.ch04.entity.Student">
        <!-- 映射主键 -->
        <id property="stuId" column="stu_id"/>
        <!-- 映射其他字段-->
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
        <!-- 多对一,班级映射 - 查询一个对象就使用<association>-->
        <association property="classInfo">
            <!-- 映射班级信息 -->
            <id property="cid" column="c_id"/>
            <result property="className" column="class_name"/>
        </association>
        <!-- 多对多映射住址 - 查询一个集合就使用<collection>-->
        <collection property="addresses" ofType="edu.nf.ch04.entity.Address">
            <id property="aid" column="a_id"/>
            <result property="address" column="address"/>
        </collection>
    </resultMap>

    <select id="getStuById" parameterType="int" resultMap="stuMap">
        select s.stu_id, s.stu_name, s.stu_age, c.class_name, a.address
        from stu_info s join class_info c on s.c_id = c.c_id join stu_addr sa
        on s.stu_id = sa.stu_id join addr_info a on a.a_id = sa.addr_id
        where s.stu_id = #{sid};
    </select>
</mapper>

2、一对多

一对多关联学生, 一对多和多对多使用collection映射, 查询时注意要查询一这一方的id

<?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="edu.nf.ch04.dao.ClassDao">

    <resultMap id="classMap" type="edu.nf.ch04.entity.ClassInfo">
        <id property="cid" column="c_id"/>
        <result property="className" column="class_name"/>
        <!-- 一对多关联学生, 一对多和多对多使用collection映射, 查询时注意要查询一这一方的id -->
        <!-- ofType用于指定映射集合中的实体类型-->
        <collection property="students" ofType="edu.nf.ch04.entity.Student">
            <id property="stuId" column="stu_id"/>
            <result property="stuName" column="stu_name"/>
            <result property="stuAge" column="stu_age"/>
        </collection>
    </resultMap>

    <select id="getClassInfoById" parameterType="int" resultMap="classMap">
        select c.c_id, c.class_name, s.stu_name, s.stu_age from class_info c
        join stu_info s on c.c_id = s.c_id where c.c_id = #{cid}
    </select>

</mapper>

3、一对一

<?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="edu.nf.ch04.dao.IdCardDao">

    <resultMap id="cardMapper" type="edu.nf.ch04.entity.IdCard">
        <id property="cardId" column="card_id"/>
        <result property="cardNum" column="card_num"/>
        <!-- 一对一关联学生 -->
        <association property="student">
            <id property="stuId" column="stu_id"/>
            <result property="stuName" column="stu_name"/>
            <result property="stuAge" column="stu_age"/>
        </association>
    </resultMap>

    <select id="getCardByNum" parameterType="string" resultMap="cardMapper">
        select c.card_id, c.card_num, s.stu_name, s.stu_age from card_info c
        join stu_info s on s.stu_id = c.stu_id where c.card_num = #{cardNum}
    </select>

</mapper>

七、动态查询

部分Dao案列

public interface StuDao {

    /**
     * 多条件查询
     * 多个条件可以使用实体类封装也可以使用map集合封装
     * @param params
     * @return
     */
    List<Student> listStudents(Map<String, Object> params);

    /**
     * 多条件动态查询
     * @param params
     * @return
     */
    List<Student> listStudents2(Map<String, Object> params);

    /**
     * 根据年龄范围查询
     * @param ages
     * @return
     */
    List<Student> listStudents3(List<Integer> ages);

    List<Student> listStudents4(Integer[] ages);

    /**
     * 修改操作
     * @param stu
     */
    void updateStu(Student stu);

    /**
     * 批量更新操作
     * @param params
     */
    void batchAdd(List<Student> params);

    /**
     * 批量删除
     * @param stuId
     */
    void batchDelete(List<Integer> stuId);
}

在mybatis中使用

<?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="edu.nf.ch05.dao.StuDao">
    <!-- 定义resultMap映射查询结果集 -->
    <resultMap id="stuMap" type="edu.nf.ch05.entity.Student">
        <id property="stuId" column="stu_id"/>
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
    </resultMap>
    <!-- 动态条件查询(多个条件),结合<where>标签和<if>标签来实现 -->
    <select id="listStudents" parameterType="map" resultMap="stuMap">
        select stu_id,stu_name,stu_age from student_info
        <where>
            <if test="uname != null and uname != ''">
                stu_name = #{uname}
            </if>
            <if test="age != null">
                and stu_age = #{age}
            </if>
        </where>
        order by stu_id desc;
    </select>

    <!-- 动态条件选择,使用<choose>标签 -->
    <!-- <when>标签:多个条件,当第一个满足条件后,就不管后面的条件 -->
    <!-- <otherwise>标签:不管前面的条件成不成立,能都执行<otherwise>标签里的语句 -->
    <select id="listStudents2" parameterType="map" resultMap="stuMap">
        select stu_id,stu_name,stu_age from student_info
        <choose>
            <when test="uname != null and uname != ''">
                where stu_name = #{uname}
            </when>
            <when test="age != null">
                where stu_age = #{age}
            </when>
            <otherwise>
                order by stu_id desc;
            </otherwise>
        </choose>
    </select>


    <!-- 使用<forEach>标签循环参数,运用于or或in子句查询操作 -->
    <!-- 如果使用list,那么使用的时候list -->
    <select id="listStudents3" parameterType="collection" resultMap="stuMap">
        select stu_id,stu_name,stu_age from student_info
        <where>
            stu_age in
            <if test="list != null">
                <foreach collection="list" item="age" open="(" separator="," close=")">
                    #{age}
                </foreach>
            </if>
        </where>
    </select>

    <!-- 注意:当参数是数组的时候,parameterType的值collection(collection包括list集合、数组等) -->
    <!-- 如果使用数组,那么使用的是array -->
    <select id="listStudents4" parameterType="collection" resultMap="stuMap">
        select stu_id,stu_name,stu_age from student_info
        <where>
            stu_age in
            <if test="array != null">
                <foreach collection="array" item="age" open="(" separator="," close=")">
                    #{age}
                </foreach>
            </if>
        </where>
    </select>

    <!-- 动态更新,使用<set>标签实现动态更新字段 -->
    <update id="updateStu" parameterType="edu.nf.ch05.entity.Student">
        update student_info
        <set>
            <if test="stuName != null and stuName != ''">
                stu_name = #{stuName},
            </if>
            <if test="stuAge != null">
                stu_age = #{stuAge}
            </if>
        </set>
        where stu_id = #{stuId}
    </update>

    <!-- 批量添加 -->
    <insert id="batchAdd" parameterType="collection">
        insert into student_info(stu_name,stu_age) values
        <foreach collection="list" item="stu"  separator=",">
            (#{stu.stuName},#{stu.stuAge})
        </foreach>
    </insert>

    <!-- 批量删除:同理于范围查询 -->
    <delete id="batchDelete" parameterType="collection">
        delete from student_info
        where stu_id in
        <if test="list != null">
            <foreach collection="list" item="stuId" open="(" separator="," close=")">
                #{stuId}
            </foreach>
        </if>

    </delete>
</mapper>

测试代码

public class StuDaoTest {
    @Test
    public void listStudentsTest() {
        StuDao dao = new StuDaoImpl();
        Map<String, Object> map = new HashMap<>();
	   // map.put("uname","张三");
        map.put("age", 18);
        List<Student> list = dao.listStudents(map);
        list.forEach(stu -> System.out.println(stu.getStuName()));
    }

    @Test
    public void listStudents2Test() {
        StuDao dao = new StuDaoImpl();
        Map<String, Object> map = new HashMap<>();
        map.put("uname", "张三");
        map.put("ag e", 18);
        List<Student> list = dao.listStudents2(map);
        list.forEach(stu -> System.out.println(stu.getStuName()));
    }

    @Test
    public void listStudents3Test() {
        StuDao dao = new StuDaoImpl();
        List<Integer> age = Arrays.asList(19, 20, 21);
        List<Student> list = dao.listStudents3(age);
        list.forEach(stu -> System.out.println(stu.getStuName()));
    }

    @Test
    public void listStudents4Test() {
        StuDao dao = new StuDaoImpl();
        Integer[] ages = {19, 21};
        List<Student> list = dao.listStudents4(ages);

        list.forEach(stu -> System.out.println(stu.getStuName()));
    }

    @Test
    public void updateStuTest() {
        StuDao dao = new StuDaoImpl();
        Student stu = new Student();
        stu.setStuName("盈盈");
        stu.setStuAge(22);
        stu.setStuId(1);
        dao.updateStu(stu);
    }

    @Test
    public void batchAddTest() {
        StuDao dao = new StuDaoImpl();
        Student stu1 = new Student();
        stu1.setStuName("张三丰");
        stu1.setStuAge(18);
        Student stu2 = new Student();
        stu2.setStuName("wangl");
        stu2.setStuAge(22);
        List<Student> list = Arrays.asList(stu1,stu2);
        dao.batchAdd(list);
    }

    @Test
    public void batchDeleteTest() {
        StuDao dao = new StuDaoImpl();
        List<Integer> list = Arrays.asList(6,7);
        dao.batchDelete(list);
    }
}

八、使用注解

注解的使用:

​ 1.使用@Options注解来获取增长的主键

​ 2.在多表查询的时候,需要现在mapper.xml中声明resultMap,然后使用@ResultMap注解

​ 注解的value指定为“dao接口的完整类名,resultMap的id”

​ 3.当在dao接口上使用注解映射sql时,在mybatis.xml中配置映射文件时,可以使用

​ 或

​ 注意:只能二选一

public interface StuDao {
    /**
     * 添加
     *
     * @param student
     */
    @Insert("insert into student_info(stu_name, stu_age) values (#{stuName},#{age})")
    // 使用Options注解来获取自增长的主键
    @Options(useGeneratedKeys = true, keyProperty = "uid")
    void save(Student student);

    /**
     * 修改
     *
     * @param student
     */
    @Update("update student_info set stu_name = #{stuName},stu_age = #{age} where stu_id = #{uid}")
    void update(Student student);

    /**
     * 删除
     * @param uid
     */
    @Delete("delete from student_info where stu_id = #{uid}")
    void delete(int uid);

    /**
     * 查询
     * 方式一:使用as别名
     * 方式二:使用驼峰命名法,前提是(在数据库是用的是stu_id,那么在实体中定义字段的时候应该使用stuId)
     * @param uid
     * @return
     */
    @Select("select stu_id as uid,stu_name as stuName,stu_age as age from student_info where stu_id = #{uid}")
    @ResultType(Student.class)
    Student getStudentById(int uid);

    /**
     * 查询所以的班学生信息和班级信息
     * @return
     */
    @Select("select s.stu_id,s.stu_name,s.stu_age, c.class_name from student_info s " +
            "join class_info c on c.c_id = s.c_id")
    // 如果使用@ResultMap注解,那么映射配置还是放在xml中
    // 注解的value指定为“dao接口的完整类名,resultMap的id”
    @ResultMap("edu.nf.ch06.dao.StuDao.stuMap")
    List<Student> listStudents();
}

查询:

​ 方式一:使用as别名

​ 方式二:使用驼峰命名法,前提是(在数据库是用的是stu_id,那么在实体中定义字段的时候应该使用stuId,以此类推)

<?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="edu.nf.ch06.dao.StuDao">
    <resultMap id="stuMap" type="edu.nf.ch06.entity.Student">
        <id property="uid" column="stu_id"/>
        <result property="stuName" column="stu_name"/>
        <result property="age" column="stu_age"/>
        <!-- 关联班级 -->
        <association property="classInfo">
            <id property="cid" column="c_id"/>
            <result property="className" column="class_name"/>
        </association>
    </resultMap>

</mapper>

<?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>
    <typeAliases>
        <package name="edu.nf.ch06.entity"/>
    </typeAliases>

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/pms?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;timeZone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="wyy"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 映射配置文件,当如果使用了mapper映射,里面会指定namespace的dao完整类名,下面的dao接口就不需要在指定了 -->
        <mapper resource="mappers/StudentMapper.xml"/>
        <!-- 当在dao接口上使用注解映射sql时,这里就使用class属性指dao接口的完整类名 -->
<!--        <mapper class="edu.nf.ch06.dao.StuDao"/>-->

        <!-- 也可以使用package标签指定dao接口的包即可 -->
<!--        <package name="edu.nf.ch06.dao"/>-->
    </mappers>
</configuration>

九、分页查询

1、内存查询

内存查询:是mybatis中提供了一个RowBuonds对象来进行简单的内存分页查询

这种方式是将全部数据查询出来缓存到内存中,接着在内存中进行分页逻辑

注意:当数据量大的时候这样方式不推荐,

案列:

public interface CityDao {
    /**
     * 内存分页
     * mybatis提供了一个RowBounds对象来进行简单的内存分页
     * 这种方式是将全部数据查询出来缓存到内存中,接着在内存中进行分页逻辑(当数据量大的时候这种方式不推荐)
     * @param rowBounds
     * @return
     */
    List<City> listCity(City city, RowBounds rowBounds);
}
public class CityDaoTest {
    @Test
    public void listCity(){
        CityDao dao = new CityDaoImpl();
        // 创建分页对象RowBounds
        RowBounds rb = new RowBounds(0,10);

        City city = new City();
        city.setProvince("广东");
        List<City> list = dao.listCity(city,rb);
        list.forEach(c -> System.out.println(c.getCityName()));
    }
}
    <!--查询整张表的数据-->
    <select id="listCity" resultType="edu.nf.ch07.entity.City">
        select city_id as cityId,city_name as cityName,city_code as cityCode,province from city_info
        <where>
            <if test="province != null and province != ''">
                province = #{province}
            </if>
        </where>
    </select>

2、物理查询

物理查询:使用PageHelper分页,这种分页方式是物理查询

​ PageHelper插件会根据当前使用的数据库类型动态

​ 生成相应的分页语句,因为在编写sql时无需考虑分页的sql方言

​ 使用@Param注解标识当前页(pageNum)和每页显示记录数(pageSize)

注意:使用分页时,一定要使用pageNum和pageSize为注解名

1)依赖pagehelper插件
 <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.3.3</version>
 </dependency>
2)在mybatis.xml中配置pagehelper插件
<!-- 配置插件 -->
    <plugins>
        <!-- 配置PageHelper分页插件 -->
        <!-- PageInterceptor(分页拦截器),主要将原来地收起来 语句进行拦截处理,根据当前使用的数据库类型动态生成相应的分页语句 -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 指定数据库方言 -->
            <property name="helperDialect" value="mysql"/>
            <!-- 启用分页参数的注解支持 -->
            <property name="supportMethodsArguments" value="true"/>
            <!-- 分页合理化 -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
3)案列
public interface CityDao {
    /**
     * 使用PageHelper分页,这种分页方式是物理分页,
     * PageHelper插件会根据当前使用的数据库类型动态
     * 生成相应的分页语句,因为在编写sql时无需考虑分页的sql方言
     * 使用@Param注解标识当前页(pageNum)
     * 和每页显示记录数(pageSize)
     * @param city
     * @param pageNum 第几页
     * @param pageSize 每页几天
     * @return
     */
    List<City> listCity2(@Param("city") City city, @Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize);
}
<?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="edu.nf.work04.dao.CityDao">

    <!-- 使用@Param注解绑定查询参数,或使用下标(param1、param2...) -->
    <select id="listCity" resultType="edu.nf.work04.entity.City">
        select city_id as cityId,city_name as cityName,city_code as cityCode,province from city_info
        <where>
            <if test="city.province != null and city.province != ''">
                province = #{city.province}
            </if>
            <if test="city.cityName != null and city.cityName != ''">
                and city_name = #{city.cityName}
            </if>
        </where>
    </select>

</mapper>

public class CityDaoTest {
    @Test
    public void listCityTest(){
        CityDao dao = new CityDaoImpl();
        City city = new City();
        city.setProvince("广东");
	    // city.setCityName("番禺");
        List<City> list = dao.listCity(city, 1, 10);

        // 创建分页信息对象
        PageInfo<City> pageInfo = new PageInfo<>(list);
        System.out.println(list);
        System.out.println("当前页:" + pageInfo.getPageNum());
        System.out.println("上一页:" + pageInfo.getPrePage());
        System.out.println("下一页:" + pageInfo.getNextPage());
        System.out.println("总页数:" + pageInfo.getPages());
        System.out.println("每页记录数:" + pageInfo.getPageSize());
        System.out.println("总记录数:" + pageInfo.getTotal());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WyuanY.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值