mybatis

1、引言


1.1 什么是框架?

软件的半成品,解决了软件开发过程当中的普适性问题,从而简化了开发步骤,提供了开发的效率。

1.2 什么是ORM框架?
1.3 使用JDBC完成ORM操作的缺点?
  • 存在大量的冗余代码。
  • 手工创建 Connection、Statement 等。
  • 手工将结果集封装成实体对象。
  • 查询效率低,没有对数据访问进行过优化(Not Cache)。

2、MyBatis框架


2.1 概念
  • MyBatis本是Apache软件基金会的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了Google Code,并且改名为MyBatis 。2013年11月迁移到Github。
  • MyBatis是一个优秀的基于Java的持久层框架,支持自定义SQL,存储过程和高级映射。
  • MyBatis对原有JDBC操作进行了封装,几乎消除了所有JDBC代码,使开发者只需关注 SQL 本身。
  • MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回。
2.2 访问与下载

官方网站:http://www.mybatis.org/mybatis-3/

下载地址:https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.1

3、Myabtis入门(开发步骤)


3.1 pom.xml中引入MyBatis核心依赖
 <!-- 导入Mybatis的依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>
<!-- 导入mysql依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
3.2 创建MyBatis核心配置文件

在resource路径下创建并配置mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--
    xml文件的约束
    dtd约束:注意xml标签的顺序有要求
-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--mybatis的核心配置-->
<configuration>

    <!--mybatis环境配置 default:选择环境配置 -->
    <environments default="development">
        <!--mybatis具体环境配置-->
        <environment id="development">
            <!--mybatis的事务管理配置,默认使用的是JDBC的事务管理(未来使用Spring的事务管理) -->
            <transactionManager type="JDBC"/>
            <!--mybatis的数据源配置(配置数据类的连接信息),默认使用的是JDBC的数据源(未来使用Druid数据源)-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///java2101"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 关联接口的映射配置文件   -->
    <mappers>
        <mapper resource="EmpMapper.xml"/>
    </mappers>
</configuration>
3.3 定义实体类
@Data 
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
}
3.4 创建Mapper接口
public interface EmpMapper {
    List<Emp> selectAll();
}
3.5 配置映射文件
<?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">
<!--
    mybatis 映射配置文件
    namespace:命名空间(区分不同的接口,namespace要与接口的一致)
-->
<mapper namespace="com.qf.mapper.EmpMapper">
    <!--
      select标签:表示查询操作
      id属性:必填,表示接口的中方法的名称(完全一致)
      resultType属性:返回的类型,必须要写全限定名
                  无论查询的结果是单个的实体类,还是List集合,都写单一类型
                  List<Emp>、Emp
      -->
    <select id="selectAll" resultType="com.qf.pojo.Emp">
        select * from emp
    </select>
</mapper>
3.6 关联映射文件
<!-- 关联接口的映射配置文件   -->
<mappers>
    <mapper resource="EmpMapper.xml"/>
</mappers>
3.7 编写测试类
public class MybatisTest {
    @Test
    public void test01() throws IOException {
        //1、获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        //2、通过sfb获取SqlSessionFactory对象  (加载mybatis的核心配置文件)
        SqlSessionFactory sf = sfb.build(Resources.getResourceAsStream("mybatis-config.xml"));
        //3、通过sf获取SqlSession对象。
        SqlSession sqlSession = sf.openSession();
        //4、通过SqlSession对象获取Mapper对象(EmpMapper接口的实现类是由Mybatis使用动态代理技术实现的)
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        //最终的目的(获取EmpMapper的对象,对象selectAll方法)
        List<Emp> empList = empMapper.selectAll();
        for (Emp emp : empList) {
            System.out.println(emp);
        }
    }
}

4、mybatis三种开发方式


4.1 方式1(开发常用)
  • 编写Mapper接口
  • 编写映射文件
  • 通过SqlSession获取Mapper对象,调用对应的方法

与入门案例一致

4.2 方式2
  • 编写映射文件
  • 通过SqlSession调用对应的方法

映射文件

<?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:命名空间,用于标识Mapper映射文件
-->
<mapper namespace="empMapper">
    <select id="getAll" resultType="com.qf.pojo.Emp">
        select * from emp
    </select>
</mapper>

测试类

public class MyBatisTest02 {
    @Test
    public void test01() throws IOException {
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        SqlSessionFactory sf = sfb.build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sf.openSession();
        List<Object> list = sqlSession.selectList("empMapper.getAll");
        //最终的目的:调用xml映射文件中的getAll方法
        list.stream().forEach(System.out::println);
    }
}

4.3 方式3
  • 编写Mapper接口。使用注解
  • 通过SqlSession获取Mapper对象,调用对应的方法

Mapper接口

public interface EmpMapper {
    @Select("select * from emp")
    List<Emp> findAll();
//  @Select("select * from emp where empno = #{empno}")
//  Emp selectEmpById(int empno);
}

测试类

@Test
public void test01() throws IOException {
    SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    SqlSessionFactory sf = sfb.build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sf.openSession();
    EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
    List<Emp> empList = empMapper.findAll();
    empList.stream().forEach(System.out::println);
}

5、mybatis开发细节


5.1 properties配置文件

对于mybatis-config.xml的核心配置中,如果存在需要频繁改动的数据内容,可以提取到properties中。

driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///java2101
username=root
password=123456

修改mybatis-config.xml。数据源配置

<environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </dataSource>
</environment>

5.2 类型别名

为实体类定义别名,提高书写效率。

<!--  设置类型别名    -->
<typeAliases>
    <!-- 只能给单个的类型设置别名      -->
    <!-- <typeAlias type="com.qf.pojo.Emp" alias="cxk"/>-->
    <!-- 给整个包下的类设置别名   默认的别名就是类型的名称   -->
    <package name="com.qf.pojo"/>
</typeAliases>

5.3 创建log4j配置文件

pom.xml添加log4j依赖

<!-- 引入日志依赖 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

添加log4j.properties文件

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

日志级别说明

级别描述
ALL LEVEL打开所有日志记录开关;是最低等级的,用于打开所有日志记录。
DEBUG输出调试信息;指出细粒度信息事件对调试应用程序是非常有帮助的。
INFO输出提示信息;消息在粗粒度级别上突出强调应用程序的运行过程。
WARN输出警告信息;表明会出现潜在错误的情形。
ERROR输出错误信息;指出虽然发生错误事件,但仍然不影响系统的继续运行。
FATAL输出致命错误;指出每个严重的错误事件将会导致应用程序的退出。
OFF LEVEL关闭所有日志记录开关;是最高等级的,用于关闭所有日志记录。
5.4 配置模板
  • 配置mybatis模板
  • 配置mapper映射模板

6、mybatis实现增删改查

6.1 查询

标签:< select id="" resultType="" >

6.1.1 传递一个参数
/**
 * 单个参数的查询
 *   在映射文件中通过#{参数的名称}即可获取
 *   特点:如果参数只有一个,那么其实这个参数名称无所谓,可以写任意值。但是最好一致
 *
 *    使用${参数名称}也可以获取,但是在3.4.x版本中不能直接使用${参数名称}获取
 *    解决:需要在参数上加一个注解:@Param
 *
 *
 *  总结:
 *      方法中传递参数在mapper映射文件中可使用#{}或者是${}进行获取
 *      #{}   在取值的时候只用是预加载的SQL,所以可以防止SQL注入且会自动加上 ""
 *      ${}   在取值的时候,不会加上 ""   ,需要手动加上'${参数名称}'
 *            ${}在3.4.x版本中不能直接使用${参数名称}获取,需要在参数上加一个注解:@Param
 *      能用#{}取值就不要使用${}取值
 *      ${}的应用场景
 *          在sql传递的参数不希望加上'' 则使用${} 获取参数值
 */
Emp selectOne(@Param("xingming") String name);

/**
 * @param o  表示排序的方式
 */
List<Emp> selectAllEmp(String o);

<select id="selectOne" resultType="emp">
    select * from emp where ename = '${xingming}'
</select>

<select id="selectAllEmp" resultType="emp">
    select * from emp order by sal ${o}
</select>

6.1.2 传递多个参数【注意】
/**
 * 传递两个及其以上的参数
 *
 * 在mybatis中,如果参数个数2个以上的时候,它会将这个参数封装到map集合中。
 *   且使用param1~paramN作为key,所以在mapper映射文件中获取参数需要使用#{param1~param2}进行获取
 *
 *  但是在开发中我们希望使用自己的名称,需要加上@Param注解
 */
List<Emp> selectByCondition(@Param("name") String name,@Param("sal") double sal);

<select id="selectByCondition" resultType="emp">
    select * from emp where ename = #{name} and sal > #{sal}
</select>

6.1.3 传递对象参数
/**
* 传递的参数是一个对象
*  那么在mapper映射文件中直接使用对象的属性名获取值
*/
List<Emp> selectByCondition1(Emp emp);

<select id="selectByCondition1" resultType="emp">
    select * from emp where ename = #{ename} and sal > #{sal} and deptno = #{deptno}
</select>

6.1.4 传递Map集合参数
/**
* 参数的参数是一个Map集合
*  那么在mapper映射文件中直接使用Map中的key获取值
*/
List<Emp> selectByCondition2(Map map);

<select id="selectByCondition2" resultType="emp">
    select * from emp where ename = #{ename} and sal > #{sal} and deptno = #{deptno}
</select>

6.2 模糊查询
/**
 * 模糊查询
 *   因为使用模糊查询。需要在参数的两边加上%
 *   解决方案1:在传递的参数的时候,将%拼接好
 *   解决方案2:在获取参数的时候使用${}获取    如:'%${ename}%'
 *   解决方案3:在mapper映射文件中的sql语句中使用字符串拼接函数 concat('%',#{ename},'%');
 */
List<Emp> selectByLike(String ename);

<select id="selectByLike" resultType="emp">
    select * from emp where ename like concat('%',#{name},'%')
</select>

6.3 修改

标签:< update id="" >

接口方法

int updateUser(User user);

映射文件

<update id="updateUser">
    update tb_user set username = #{username},password=#{password} where id = #{id};
</update>

测试代码

@Test
public void test03() throws IOException {
    SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    SqlSessionFactory sf = sfb.build(Resources.getResourceAsReader("mybatis-config.xml"));
    SqlSession sqlSession = sf.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = new User(6,"cxk","abc");
    int count = userMapper.updateUser(user);
    System.out.println(count);
    //注意:在mybatis中的更新操作,需要提交事务
    sqlSession.commit();
}

6.4 删除

标签:< delete id="" >

接口方法

int deleteUser(int id);

映射文件

<delete id="deleteUser">
    delete from tb_user where id = #{id}
</delete>

测试代码

@Test
public void test02() throws IOException {
    SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    SqlSessionFactory sf = sfb.build(Resources.getResourceAsReader("mybatis-config.xml"));
    SqlSession sqlSession = sf.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int count = userMapper.deleteUser(5);
    System.out.println(count);
    //注意:在mybatis中的更新操作,需要提交事务
    sqlSession.commit();
}

6.5 增加

标签:< insert id="" >

接口方法

int insertUser(User user);

映射文件

<insert id="insertUser">
    insert into tb_user (username,password) values (#{username},#{password})
</insert>

测试代码

@Test
public void test01() throws IOException {
    SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    SqlSessionFactory sf = sfb.build(Resources.getResourceAsReader("mybatis-config.xml"));
    SqlSession sqlSession = sf.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = new User("张三丰","123");
    int count = userMapper.insertUser(user);
    System.out.println(count);
    //注意:在mybatis中的更新操作,需要提交事务
    sqlSession.commit();
    System.out.println(user.getId());
}

6.6 主键回填
6.6.1 通过last_insert_id()查询主键(自增主键)

方式1:通过selectKey标签将查询的id回填到指定属性中

标签:< selectKey id="" parameterType="" order=“AFTER|BEFORE”>

<!--
     keyProperty 主键的属性
     order:在执行之前获取还是在执行之后获取
     resultType 主键的返回值类型
-->
<insert id="insertUser1" >
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
    insert into tb_user (username,password) values (#{username},#{password})
</insert>

6.6.2 直接映射主键(自增主键)

方式2:使用useGeneratedKeys使用生成的id,并回填写到指定的属性中

<!--  
  	useGeneratedKeys:使用自动生成的id
    keyProperty:将生成的id添加到指定的属性中,id属性值表示的是实体类中的属性名
-->
<insert id="insertUser1" useGeneratedKeys="true" keyProperty="id">
    insert into tb_user (username,password) values (#{username},#{password})
</insert>

7、ORM映射【重点


7.1 MyBatis自动ORM失效

MyBatis只能自动维护库表”列名“与”属性名“相同时的一一对应关系,二者不同时,无法自动ORM。

7.2 方案一:列的别名

在SQL中使用 as 为查询字段添加列别名,以匹配属性名

<select id="getAll1" resultType="product">
    select p_id pid,t_id tid,p_name name,p_time time,p_price price ,
    p_state state ,p_image image, p_info info,isdel del from product;
</select>

7.3 方案二:直接使用Map集合映射结果
<select id="getAll2" resultType="map">
    select * from product;
</select>

//解决方法2:直接返回一个Map集合
List<Map<String,Object>> getAll2();

7.4 方案三:自定义结果映射(ResultMap)
<!-- resultMap属性 表示自定义映射的id   -->
<select id="getAll3" resultMap="productMap" >
    select * from product;
</select>

<!-- resultMap标签  表示自定义映射   id:唯一标识   type:映射类型    -->
<resultMap id="productMap" type="product">
    <!-- id标签一般表示主键   result标签一般表示普通字段  (不是必须的)   -->
    <!-- 属性:d
          column 表示数据库中的字段名  property表示实体类中的属性名
          djavaType 表示java中的类型   jdbcType表示数据类型中数据类型(mybatis可以自动识别)  -->
    <id column="p_id" property="pid"/>
    <result column="t_id" property="tid"/>
    <result column="p_name" property="name"/>
    <result column="p_time" property="time"/>
    <result column="p_price" property="price"/>
    <result column="p_info" property="info"/>
    <result column="p_state" property="state"/>
    <result column="p_image" property="image"/>
    <result column="isdel" property="del"/>
</resultMap>

8、MyBatis高级映射

8.1 表之间的关系

实体间的关系:关联关系

  • OneToOne:一对一关系(person— passport)
  • OneToMany:一对多关系(dept— emp)
  • ManyToMany:多对多关系(student— teacher)
8.2 OneToOne

SQL参考person表和passport表

三种实现方案

  • 直接返回一个Map集合
  • 实体类中进行关联,mapper中做映射
  • 分步查询,实现懒加载(了解)
8.2.1 方案一:返回Map

映射代码

//1、直接将连表查询的结果映射到Map中(写一个公共类(将两个表的写到一个新的类中)) (一般不推荐这样操作)
List<Map<String,Object>> getAll1();

<select id="getAll1" resultType="map">
    select * from person p INNER JOIN passport pp on p.pid = pp.id;
</select>

8.2.2 方案二:实体类关联

实体类关联

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String phone;
    private String pid;
    private Passport passport;
}

映射代码

<select id="getAll2" resultMap="personMap">
    select p.*,pp.id p_id,pp.info,pp.fromAdd ,pp.toAdd , pp.uid from person p INNER JOIN passport pp on p.pid = pp.id;
</select>
<resultMap id="personMap" type="person">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="age" property="age"/>
    <result column="phone" property="phone"/>
    <result column="pid" property="pid"/>
    <!--
            association 一对一的关联映射
                    property:实体类中属性名称(在Person类中定义的Passport属性的名称)
                    javaType:映射对应java类型
          -->
    <association property="passport" javaType="com.qf.pojo.Passport">
        <id column="p_id" property="id"/>
        <result column="info" property="info"/>
        <result column="fromAdd" property="fromAdd"/>
        <result column="toAdd" property="toAdd"/>
        <result column="uid" property="uid"/>
    </association>
</resultMap>

8.2.3 方案三:分步查询

实体类关联

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String phone;
    private String pid;
    private Passport passport;
}

映射代码

<select id="getAll3" resultMap="personMap1">
    select * from person
</select>
<resultMap id="personMap1" type="person">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="age" property="age"/>
    <result column="phone" property="phone"/>
    <result column="pid" property="pid"/>
   <!--
    association 一对一的关联映射
         property:实体类中属性名称(在Person类中定义的Passport属性的名称)
         javaType:映射对应java类型
         select:分步查询的方法
         column:根据指定外键做查询
      fetchType:设置懒加载   eager:积极加载(无论是否使都会查询)  lazy:懒加载(什么时候使用什么时候查询)
 	-->
    <association property="passport"
                 javaType="com.qf.pojo.Passport"
                 select="selectPassport"
                 column="pid"
                 fetchType="lazy">
    </association>
</resultMap>

<select id="selectPassport" resultType="passport" >
    select * from passport where id = #{pid}
</select>

8.3 OneToMany

SQL参考emp表和dept表

8.3.1 方案一:返回Map
//此方式不适合一对多的查询情况

8.3.2 方案二:实体类关联

实体类关联

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Integer deptno;
    private String dname;
    private String location;
    //一对多
    private List<Emp> empList;
}

映射代码

<select id="getAll2" resultMap="deptMap">
    select * from dept d INNER JOIN emp e on d.deptno = e.deptno;
</select>

<resultMap id="deptMap" type="dept">
    <id column="deptno" property="deptno"/>
    <result column="dname" property="dname"/>
    <result column="location" property="location"/>
    <!--
              collection:一对多的关联映射
                    property:关联的实体类中的集合的属性名
                    ofType:  集合泛型的类型
        -->
    <collection property="empList" ofType="emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="job" property="job"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="sal" property="sal"/>
        <result column="comm" property="comm"/>
        <result column="deptno" property="deptno"/>
        <result column="image" property="image"/>
    </collection>
</resultMap>

8.3.3 方案三:分步查询

实体类关联

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Integer deptno;
    private String dname;
    private String location;
    //一对多
    private List<Emp> empList;
}

映射代码

<select id="getAll3" resultMap="deptMap1">
        select * from dept;
    </select>
    <resultMap id="deptMap1" type="dept">
        <id column="deptno" property="deptno"/>
        <result column="dname" property="dname"/>
        <result column="location" property="location"/>
        <collection property="empList" 
                    ofType="emp" 
                    select="selectEmp" 
                    column="deptno" 
                    fetchType="lazy"/>
    </resultMap>

    <select id="selectEmp" resultType="emp">
        select * from emp where deptno = #{deptno}
    </select>

8.4 ManyToMany

SQL参考student表和teacher表

8.4.1 方案一:实体类关联

实体类关联

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Double score;
    private List<Teacher> teacherList;
}

映射代码

<select id="getAll1" resultMap="studentMap">
    select s.id sid,s.name sname , s.score score , t.*  
    from student s INNER JOIN t_s ts on s.id = ts.sid INNER JOIN teacher t on t.id = ts.tid
</select>
<resultMap id="studentMap" type="student">
    <id column="sid" property="id"/>
    <result column="sname" property="name"/>
    <result column="score" property="score"/>
    <!--  一对多的关联映射      -->
    <collection property="teacherList" ofType="teacher">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="job" property="job"/>
    </collection>
</resultMap>

8.4.2 方案二:分步查询

与上面一对多的分步查询一致

注意:连表查询的时候,如果两张表有同名字段,在写sql语句的时候要取别名

9、动态SQL

MyBatis的映射文件中支持在基础SQL上添加一些逻辑操作,并动态拼接成完整的SQL之后再执行,以达到SQL复用、简化编程的效果。

9.1 < sql >

sql标签的作用是提取公共的sql代码片段

  • sql id属性:唯一标识
  • include refid属性:参照id
<!--  定义SQL片段:抽取公共的SQL语句  -->
<sql id="productSql">
    p_id pid,t_id tid,p_name name,p_time time,p_price price ,
    p_state state ,p_image image, p_info info,isdel del
</sql>
<!-- 引用片段 -->
<select id="selectProductByCondition" resultType="product">
        select  <include refid="p_col"/>  from product
</select>

9.2 < if >

if标签的作用适用于条件判断

  • test 属性:判断条件(必填)
<!--
    if标签用于判断使用
        注意:
            1、在test中获取属性值的时候,不需要加上#{},在sql语句中获取属性值要加上#{}
            2、在sql语句中进行使用特殊字符,最好不要使用 > 或者 <,应该使用 &gt;  &lt;
-->
<select id="selectByCondition" resultType="product">
    select <include refid="productSql"/> from product  where 1 = 1
    <if test="name != null">
        and p_name like concat('%',#{name},'%')
    </if>
    <if test="time != null">
        and p_time  &gt; #{time}
    </if>
    <if test="price != null">
        and p_price &gt; #{price}
    </if>
    <if test="state != null">
        and p_state &gt; #{state}
    </if>
</select>

9.3 < where >

where 标签作用是添加where条件。 如果没有条件,不会加上where。 会自动去掉前的and|or等关键字

<!--
    where标签用于添加where条件
        特点:
            1、如果where有条件自动加上where关键字,如果没有则不会where关键字
            2、会自动去除前面的and或者or等关键字
-->
<select id="selectByCondition" resultType="product">
    select <include refid="productSql"/> from product
    <where>
        <if test="name != null">
            and p_name like concat('%',#{name},'%')
        </if>
        <if test="time != null">
            and p_time  &gt; #{time}
        </if>
        <if test="price != null">
            and p_price &gt; #{price}
        </if>
        <if test="state != null">
            and p_state &gt; #{state}
        </if>
    </where>
</select>

9.4 < set >

set 标签的作用是添加set,与where类似

<!--  set标签用于添加修改的字段值
        特点:
        1、如果set有条件自动加上set关键字,如果没有则不会set关键字
        2、会自动去除后面的,
 -->
<update id="updateByCondition">
    update product
    <set>
        <if test="name != null">
            p_name = #{name},
        </if>
        <if test="time != null">
            p_time = #{time},
        </if>
        <if test="state != null">
            p_state = #{state},
        </if>
        <if test="price != null">
            p_price = #{price},
        </if>
        p_id = #{pid}
    </set>
    where p_id = #{pid}
</update>

9.5 < choose >

choose标签作用是条件选择。类似于Java中的多重if

  • choose 、when 、otherwise
<!--
    choose、when、otherwise标签用于多值判断使用类似于java中的switch...case
-->
<select id="selectOrderByCondition" resultType="product">
    select <include refid="productSql"/> from product  order by
    <choose>
        <when test="price != null">
            p_price desc
        </when>
        <when test="time != null">
            p_time desc
        </when>
        <when test="state != null">
            p_state desc
        </when>
        <otherwise>
            p_id desc
        </otherwise>
    </choose>
</select>

9.6 < trim >

< trim prefix="" suffix="" prefixOverrides="" suffixOverrides="" >代替< where > 、< set >

  • prefix 前缀
  • suffix 后缀
  • prefixOverrides 前缀覆盖
  • suffixOverrides 后缀覆盖
<!--
   trim:用灵活的定义任意的前缀和后缀,以及覆盖多余前缀和后缀
-->
<update id="updateByCondition">
    update product
    <trim prefix="set" suffixOverrides=",">
        <if test="name != null">
            p_name = #{name},
        </if>
        <if test="time != null">
            p_time = #{time},
        </if>
        <if test="state != null">
            p_state = #{state},
        </if>
        <if test="price != null">
            p_price = #{price},
        </if>
        p_id = #{pid}
    </trim>
    where p_id = #{pid}
</update>

9.7 < foreach >

foreach 标签的作用是遍历集合或者数组

参数描述取值
collection容器类型list、array、map(可以在形参上加注解改变名称)
open起始符(
close结束符)
separator分隔符,
index下标号从0开始,依次递增
item当前项任意名称(循环中通过 #{任意名称} 表达式访问)

案例1:批量增加

<!-- insert into 表名  (字段名1,字段名2,...)  values (值1,...),(值1,...) ,(值1,...)  -->
<insert id="insertProduct">
    insert into product (p_name,p_time,p_state,p_price) values
    <foreach collection="productList" item="product" separator=",">
        (#{product.name},#{product.time},#{product.state},#{product.price})
    </foreach>
</insert>

案例2:批量删除

<!-- delete from 表名 where p_id in (id1,id2,..)   -->
<delete id="deleteProduct">
    delete from product where p_id in
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</delete>

10、mybatis缓存

mybatis一共有两级缓存,分别是一级缓存和二级缓存。默认开启了一级缓存

10.1 一级缓存

在这里插入图片描述

一级缓存是mybatis中默认开启的

生命周期:在同一个SqlSession下

  • 一级缓存何时生效
    • 默认生效
  • 一级缓存何时失效
    • 1、两次查询使用不是同一个SqlSession
    • 2、手动将缓存清空
    • 3、当sqlSession关闭之后
    • 4、当两次查询操作中间,如果执行了增删改的操作,缓存失效
10.2 二级缓存

在这里插入图片描述

mybatis中二级缓存是需要手动开启

生命周期: 二级缓存是在namespace级别

  • 二级缓存生效:
    • 1、在主配置文件中开启二级缓存
    • 2、在mapper映射文件中添加标签
    • 3、在查询之间,SqlSession需要提交
    • 4、如果没有缓存配置,那么这个类需要实现序列化接口
  • 二级缓存失效
    • 1、当两次查询操作中间,如果执行了增删改的操作,二级缓存失效

开启二级缓存

<configuration>
    <!-- 开启二级缓存(当前这个版本是默认开启的)   -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    ...
</configuration>

mapper映射配置缓存

<!--
      eviction:缓存淘汰策略 FIFO(先进先出)  LRU(最近最少使用)
      flushInterval:缓存的刷新时间
      size:缓存的大小
      readOnly:缓存只读
-->
<cache  eviction="LRU"
        flushInterval="60000"
        size="512"
        readOnly="true"/>

11 、分页插件

11.1 概念

PageHelper是适用于MyBatis框架的一个分页插件,使用方式极为便捷,支持任何复杂的单表、多表分页查询操作。

11.2 访问与下载

官方网站:https://pagehelper.github.io/

下载地址:https://github.com/pagehelper/Mybatis-PageHelper

11.3 开发步骤
11.3.1 引入依赖

pom.xml中引入PageHelper依赖。

 <!-- 引入分页插件依赖 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>
11.3.2 配置MyBatis-config.xml

在MyBatis-config.xml中添加< plugins >。

<configuration>
  	<typeAliases></typeAliases>
  
   <plugins>
        <!-- 添加分页拦截器查询   -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
  
  	<environments>...</environments>
</configuration>
11.3.3 PageHelper使用
@Test
public void test01() throws IOException {
    SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    SqlSessionFactory sf = sfb.build(Resources.getResourceAsReader("mybatis-config.xml"));
    SqlSession sqlSession = sf.openSession();
    EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
    //在查询之前执行!!!!
    PageHelper.startPage(3,3);
    List<Emp> empList = empMapper.getAll();
    PageInfo pageInfo = new PageInfo(empList);
    //empList.stream().forEach(System.out::println);
    System.out.println(pageInfo);
}
11.4 PageInfo对象

PageInfo对象中包含了分页操作中的所有相关数据。

PageInfo结构图
在这里插入图片描述
11.4.1 PageInfo应用方式

使用PageInfo保存分页查询结果。

/**
 *  分页插件(物理分页 (sql语句中添加limit))
 *  1、导入pageHelper依赖
 *  2、在mybatis核心配置文件中添加插件(配置分页拦截器)
 *  3、在执行查询操作之前执行 PageHelper.startPage(当前页,每页条数)
 *  4、如果要获取完整结果,创建一个PageInfo对象即可(PageInfo pageInfo = new PageInfo(empList);)
 */

//创建一个分页信息类
PageInfo<Product> pageInfo = new PageInfo<>(productList);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值