MyBatis快速上手

一、概念

1.1、概念

  1. MyBatis是一个优秀的基于Java的持久层框架,支持自定义SQL,存储过程和高级反射
  2. MyBatis对原有的JDBC进行了封装,几乎消除了所有的JDBC代码,使用者只需关注SQL本身
  3. MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回

依赖网站:https://mvnrepository.com/

二、步骤

1、Maven项目配置MyBatis

1.导入依赖

<dependencies>
    <!--MyBatis核心依赖-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>

2.创建mybatis-config.xml配置文件,配置数据库信息

<?xml version="1.0" encoding="UTF-8"?>
<!--mybatis配置文件头,特点为首尾的“configuration”和“mybatis-3-config.dtd”-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
   <!--核心配置信息-->
    <environments default="shine_config">
        <!--数据库相关配置-->
        <environment id="shine_config">
            <!--事务控制类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据库连接参数-->
            <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
                <!--&转义&amp;-->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&amp;useUnicode=true&amp;useSSL=false&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="123456"></property>
            </dataSource>
        </environment>
    </environments>
</configuration>

2、开发步骤

已经完成MyBatis配置步骤

1.根据数据表编写User实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private Boolean gender;
    private Date regist_time;
}

2.编写UserDao接口

public interface UserDao {
    User queryUserById(Integer id);
}

3.在resource目录下编写UserDaoMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!--mybatismapper文件头,特点为首尾的“mapper”和“mybatis-3-mapper.dtd”-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="dao.UserDao">
    <!--描述方法-->
    <!--id为方法名,resultType为返回值类型,arg0表示参数的第一个值-->
    <!--queryUserById是Dao中的方法名-->
    <select id="queryUserById" resultType="entity.User">
        select id,username,password,gender,regist_time
        from t_user
        where id=#{arg0}
    </select>
</mapper>

4.在mybatis-config.xml配置文件中注册mapper文件

<!--注册mapper文件-->
<mappers>
    <mapper resource="UserDaoMapper.xml"/>
</mappers>

5.编写测试类TestMybatis.java

public class TestMybatis {
    public static void main(String[] args) throws IOException {
        //mybatis API
        //1.加载配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //2.构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //3.通过sqlSessionFactory创建sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.通过sqlSession获得DAO实现类的对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        //5.测试查询方法
        User user1 = mapper.queryUserById(1);
        User user2 = mapper.queryUserById(2);
        System.out.println(user1);
        System.out.println(user2);
        sqlSession.close()
    }
}
2.1一些问题

如果mapper不在常规目录(resource)下

<!--========在pom.xml文件中更改默认编译规则==========================================================-->
<build>
    <!--更改Maven编译规则-->
    <resources>
        <resource>
            <!--资源目录-->
            <directory>src/main/java</directory>
            <!--扫描资源目录下的所有xml文件-->
            <includes>
                <include>*.xml</include> <!--默认(新添加自定义则失效)-->
                <include>**/*.xml</include><!--新添加 */代表1级目录 **/代表多级目录-->
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

<!--========mybatis配置文件中注册mapper文件的路径====================================================-->
<mappers>
    <mapper resource="dao/UserDaoMapper.xml"/>
</mappers>

频繁更改环境的问题

<!--
1.在resource目录下创建jdbc-properties文件,并将mybatis配置文件中的url,driver,username,password内容复制到文件相应位置中
-->
jdbc.url = jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=UTF-8
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.username = root
jdbc.password = 123456

<!--
2.在mybatis配置文件中导入jdbc-properties文件
-->
<properties resource="jdbc-properties"></properties>

<!--
3.将mybatis配置文件的数据库连接参数更改为动态参数
-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
    <property name="driver" value="${jdbc.driver}"></property>
    <property name="url" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</dataSource>
<!--往后更改数据库连接信息只需在jdbc-properties文件中修改即可-->

类别名问题

<!--
方法1,设置某个类的别名,mapper文件中要以这个类为返回对象时,可直接使用设置的别名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
    <typeAlias type="entity.User" alias="user_shine"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="user_shine">
    select id,username,password,gender,regist_time
    from t_user
    where id=#{arg0}
</select>


<!--
方法2,定义实体类所在的包,每个实体类自动注册一个别名(也就是类名);
mapper文件中要以这个类为返回对象时,可直接写类名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
    <package name="entity"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    where id=#{arg0}
</select

日志问题

# 在resource目录下创建log4j.properties文件(固定名字)
# 运行项目就会输出日志
log4j.rootLogger=DEBUG, stdout
log4j.logger.org.mybatis.example.BlogMapper=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

三、CURD操作

3.1 查询操作参数绑定的几种方式

方式一

<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--arg0和agr1和param2表示数据的第一个值和第二个值-->
    where id=#{arg0} and username=#{agr1}
</select>

方式二

<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--param1和param2表示数据的第一个值和第二个值-->
    where id=#{param1} and username=#{param2}
</select>

方式三

<!--dao接口-->
User queryUserByIdAndPassword(@Param("id") Integer id,@Param("password") String password);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--此处的id和password是@Param注解定义的名字-->
    where id=#{id} and username=#{password}
</select>

方式四

<!--dao接口-->
User queryUserByIdAndPassword2(Map map);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--此处的id和password是Map的key-->
    where id=#{id} and username=#{password}
</select>
<!--测试操作-->
Map map = New HashMap();
map.put("id",2);
map.put("password","456");

方式五

<!--dao接口-->
User queryUserByIdAndPassword3(User user);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--此处的id和password是User类中定义的属性名-->
    where id=#{id} and username=#{password}
</select>
<!--测试操作-->
User user = new User();
user.setId(1);
user.setPassword("123")

3.2 模糊查询

模糊查询将可能返回多个对象,使用 list<>

使用concat(’%’,#{keyword},’%’)做字符串拼接

<!--dao接口-->
List<User> queryUserByUsername(@Param("username") String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
    select id,username,password,gender,regist_time
    from t_user
    <!--concat做字符串拼接-->
    where username like concat('%',#{username},'%')
</select>  

3.3 delete操作

<!--dao接口-->
void deleteUser(@Param("id") Integer id);
<!--mapper文件-->
<delete id="deleteUser" parameterType="int">
    delete form t_user
    where id = #{id}
</delete>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->

3.4 update操作

<!--dao接口-->
void updateUser(User user);
<!--mapper文件-->
<update id="updateUser" parameterType="User">
    update t_user 
    set username=#{username},password=#{password},gender={gender},regist_time=#{regist_time}
    where id=#{id}
</update>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->

3.5 insert操作

<!--dao接口-->
void insertUser(User user);
<!--mapper文件-->
<insert id="insertUser" parameterType="User">
    insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->

3.6 主键回填

当添加数据时,有可能有需要这条添加数据的id,这时候需要用到主键回填


第一种情况,主键是可自增的整型(获取到自增的主键值)

<!--dao接口-->
void insertUser(User user);

<!--mapper文件-->
<insert id="insertUser" parameterType="User">
    <!--主键回填,将新数据的ID存入java对象的主键对应的属性中-->
    <!--order指定执行顺序,这里的id指的是插入操作中的id参数-->
    <selectKey order="AFTER" resultType="int" keyProperty="id">
        select last_insert_id()
    </selectKey>
    insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>

<!--测试操作-->
User new_ser = new User(null, "shine_652", "00000", true, new Date());
mapper.insertUser(new_ser);
System.out.println(new_ser);<!--查看回填的id-->
sqlSession.commit();
sqlSession.close()

第二种情况,主键是字符串(随机生成UUID存入数据库)

<!--dao接口-->
Integer insertStudent(Student student);

<!--mapper文件-->
<insert id="insertStudent" parameterType="Student">
    <!--将主键设置为32位,mysql生成唯一的32位UUID,回填到参数id中-->
    <!--使用mysql的replace方法去除生成UUID的短很细和空格-->
    <selectKey order="BEFORE" resultType="String" keyProperty="id">
        select replace(uuid(),'-','');
    </selectKey>
    insert into t_student  values (#{id},#{name},#{gender});
</insert>

<!--测试操作-->
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student(null, "shine001", true);
mapper.insertStudent(student);
System.out.println(student);
sqlSession.commit();
sqlSession.close()

四、MyBatis工具类

4.1 封装工具类

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 java.io.IOException;
import java.io.InputStream;

/**
 * 1.加载配置
 * 2.创建SqlSessionFactory
 * 3.创建Session
 * 4.事务管理
 * 5.mapper获取
 */
public class MyBatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    //创建ThreadLocal绑定当前线程中的SqlSession对象
    private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
    static { //加载配置信息
        //1.加载配置文件
        try{
            //1.加载配置文件
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            //2.构建SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    //创建sqlSession
    public static SqlSession openSession(){
        SqlSession sqlSession = tl.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            tl.set(sqlSession);
        }
        return sqlSession;
    }

    //释放资源
    public static void closeSession(){
        SqlSession sqlSession = tl.get();
        sqlSession.close();
    }

    //提交事务
    public static void commit(){
        SqlSession sqlSession = openSession();
        sqlSession.commit();
        closeSession();
    }

    //事务回滚
    public static void rollback(){
        SqlSession sqlSession = openSession();
        sqlSession.rollback();
        closeSession();
    }

    //mapper获取
    public static <T> T getMapper(Class<T> mapper){
        SqlSession sqlSession = openSession();
        return sqlSession.getMapper(mapper);
    }
}

4.2 测试工具类

StudentDao studentMapper = MyBatisUtil.getMapper(StudentDao.class);
Student student = new Student(null, "test_util", true);
studentMapper.insertStudent(student);
MyBatisUtil.commit();

五、映射

5.1 resultMap结果地图

当数据表数据表列名与实体类属性名不一致时

  1. 在SQL语句中为列名设置别名(与实体类属性名一致)
  2. 使用resultMap结果地图
<!--定义复杂情况的,映射规则-->
<resultMap id="user_resultMap" type="User">
    <!--主键列,column表示数据表的列名,property表示实体类的属性名-->
    <id column="id" property="id"/>
    <!--普通列,column表示数据表的列名,property表示实体类的属性名-->
    <result column="username" property="username"/>
    <result column="password" property="password"/>
    <result column="gender" property="gender"/>
    <!--表列名为registTime,因为是在SQL语句中定义的别名-->
    <result column="registTime" property="regist_time"/>
</resultMap>

<select id="queryUserById" resultMap="user_resultMap">
    select id,username,password,gender,regist_time registTime
    from t_user
    where id=#{arg0}
</select>

六、关联查询

6.1 一对一

一对一关系,两个表中,主表中的一个字段对应从表中的一条数据


一对一查询注意点:

有以下两张表 (性别列用整型,0和1)

image-20220210120707944
  • 主键和外键列的值相同,只在主表实体类中写就行了

  • 创建表对应的实体类时,添加另一张表的实类类对象(关系属性)

    例如:在 Passenger实体类中添加 private Passport passport

    ​ 在 Passport实体类中添加 private Passenger passenger

  • PassengerDaoMapper.xml映射文件如下:

    一对一的resultMap中使用的是 association

<mapper namespace="dao.PassengerDao">
    <resultMap id="passenger_passport" type="Passenger">
        <id column="id" property="id"></id>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <!--passport指的是Passenger实体类中的Passport对象属性名-->
        <association property="passport" javaType="entity.Passport">
            <!--此处的表列名为passId,是在SQL语句中取的别名-->
            <id column="passId" property="id"></id>
            <result column="nationality" property="nationality"/>
            <result column="expire" property="expire"/>
        </association>
    </resultMap>
    
    <!--查询旅客和护照信息-->
    <select id="queryPassengerById" resultMap="passenger_passport">
        select t_passengers.id,t_passengers.name,t_passengers.sex,t_passengers.birthday,
               t_passports.id passId,t_passports.nationality,t_passports.expire
        from t_passengers join t_passports
        on t_passengers.id = t_passports.passengers_id
        where t_passengers.id = #{id}
    </select>
</mapper>

6.2 一对多

一对多的关系,两张数据表中,主表中的一个字段对应从表中的多条数据


有以下两张表

image-20220210135345349
  • 主键和外键列的值相同,只在主表实体类中写就行了

  • 创建表对应的实体类时,添加另一张表的实类类对象(关系属性)

    例如:主表实体类中的从表实体类对象: private List<Employee> employee

    ​ 从表实体类中的主表实体类对象: private Department department

  • PassengerDaoMapper.xml映射文件如下:

    一对多的resultMap中使用的是 collection

<mapper namespace="dao.DepartmentDao">
    <resultMap id="department_result" type="Department">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>
        <result column="location" property="location"></result>
        <!--employee是主表实体类中的对象属性名-->
        <collection property="employee" ofType="Employee" >
            <!--列名为SQL别名-->
            <id column="emp_id" property="id"></id>
            <result column="emp_name" property="name"></result>
            <result column="salary" property="salary"></result>
        </collection>
    </resultMap>

    <select id="queryDepartmentById" resultMap="department_result">
        select t_departments.id,t_departments.name,t_departments.location,
               t_employees.id emp_id,t_employees.name emp_name,t_employees.salary
        from t_departments join t_employees
        on t_departments.id = t_employees.dept_id
        where t_departments.id=#{id}
    </select>
</mapper>

6.3 多对多

多对多关系,至少三张表,一张表为中间表连接另外两张表;从中间表角度看,多对多是复杂化的一对多


有如下三张表,第三张表为中间表,两个字段都是外键

image-20220210150135528
  • 创建表对应的实体类时,添加其他表的实类类对象,中间表不用创实体类(关系属性)

    例如:在表1中添加表2的实体类对象: private List<Subject> subject

    ​ 在表2中添加表1的实体类对象: private List<Student2> students

  • PassengerDaoMapper.xml映射文件如下:

    多对多的resultMap中使用的是 collection

<!--课程关联学生查询-->
<mapper namespace="dao.SubjectDao">
    <resultMap id="subject_result" type="Subject">
        <id column="id" property="id"></id>
        <result column="name" property="name"/>
        <result column="grade" property="grade"/>
        <!--student是定义在Subject实体类中的对象属性,Student2是对象属性对应的实体类对象-->
        <collection property="students" ofType="Student2">
            <id column="stu_id" property="id"></id>
            <result column="stu_name" property="name"/>
            <result column="sex" property="sex"/>
        </collection>
    </resultMap>

    <select id="querySubjectById" resultMap="subject_result">
        select t_subjects.id,t_subjects.name,t_subjects.grade,
        	t_students.id stu_id,t_students.name stu_name,t_students.sex
        from t_subjects join t_stu_sub
        on t_subjects.id = t_stu_sub.subject_id
        join t_students
        on t_stu_sub.student_id = t_students.id
        where t_subjects.id = #{id}
    </select>
</mapper>

七、动态SQL

7.1 SQL片段抽取

在mapper映射文件中抽取出相同的SQL片段,用插入的方式使用片段,减少冗杂。

<sql id="user_field">
    select id,username,password,gender,regist_time registTime
    from t_user
</sql>

<select id="queryUserById" resultType="User">
    <include refid="user_field"/>
    where id=#{id}
</select>

7.2 if标签

当一个实体对应的Dao文件中要进行多个查询时,可以只定义一个Dao方法,在映射文件中使用If判断

// 假设User实体类中有id和username两个字段
User queryUser(User user)
<!--假设查询User两个字段的任意一个时,判断其不为空(另一个肯定为空),传入其中一个字段值查询-->
<select id="queryUser" resultType="User">
    <include refid="user_field"/>
    where 
    <if test="id!=null">
        id=#{id}
    </if>
    <if test="username!=null">
        username=#{username}
    </if>
</select>

7.3 where标签

上述假设只传入一个值,当传入两个值时

// 假设User实体类中有username和gender两个字段
User queryUser(User user)
<!--加上一个or,表示当传入两个值时,两个值都将被带入查询-->
<!--where标签可以去除当传入一个值时可能存在的or或and开头的关键字,避免带入SQL语句查询-->
<select id="queryUser" resultType="User">
    <include refid="user_field"/>
    <where>
        <if test="username!=null">
            username=#{username}
        </if>
        <if test="gender!=null">
            or gender=#{gender}
        </if>
    </where>
</select>

7.4 set标签

当一个实体对应的Dao文件中要进行多个更新时,可以只定义一个Dao方法,在映射文件中可以将set和if两个标签配合使用

User updateUser(User user)
<!--set标签可以去除字段后的逗号-->
<update id="updateUser" parameterType="User">
    update t_user
    <set>
        <if test="username!=null">
            username=#{username},
        </if>
        <if test="password!=null">
            password=#{password},
        </if>
        <if test="gender!=null">
            gender=#{gender},
        </if>
        <if test="registTime!=null">
            registTime=#{registTime}
        </if> 
    </set>
    where id = #{id}
</update>

7.5 trim标签

trim标签综合了where和set标签,可替代两个标签

<select id="queryUser" resultType="User">
    <include refid="user_field"/>
    <!--此处trim标签的作用和where一样,去除or或者and开头的关键字-->
    <trim prefix="where" prefixOverrides="or|and">
        <if test="username!=null">
            username=#{username}
        </if>
        <if test="gender!=null">
            or gender=#{gender}
        </if>
    </trim>
</select>

<!--==============================================================================================-->

<update id="updateUser" parameterType="User">
    update t_user
    <!--此处trim标签的作用和set一样,去除结尾的逗号-->
    <trim prefix="set" suffixOverrides=",">
        <if test="username!=null">
            username=#{username},
        </if>
        <if test="password!=null">
            password=#{password},
        </if>
        <if test="gender!=null">
            gender=#{gender},
        </if>
        <if test="registTime!=null">
            registTime=#{registTime}
        </if>
    </trim>
    where id = #{id}
</update>

7.6 foreach标签

批量操作使用foreach标签进行遍历


批量删除

Integer deleteManyUser(List<Integer> ids)
<delete id="deleteManyUser" parameterType="java.util.List">
    <!--delete from t_user where id in(x,x,x,x,x,x)-->
    delete from t_user where id in
    <!--collection表示遍历参数的类型,item表示每次遍历出的值,separator表示用逗号做分隔-->
    <foreach collection="list" open="(" close=")" item="id9" separator=",">
        #{id9}
    </foreach>
</delete>

批量插入

Integer insertManyUser(List<User> users)
<insert id="insertManyUser" parameterType="java.util.List">
    <!--insert into t_user values(null,x,x,x,x)-->
    insert into t_user values
    <!--open和close不规则空着-->
    <foreach collection="list" open="" close="" item="user9" separator=",">
        (null,#{user9.username},#{user9.password},#{user9.gender},#{user9.registTime})
    </foreach>
</insert>

八、缓存

缓存:内存中的一块储存控件,服务于某个应用程序,旨在将频繁读取的数据临时保存在内存中,便于二次访问

  • 无缓存:用户访问数据时,需要发起多次对数据库的访问,导致产生大量IO,读写硬盘操作,效率低下
  • 有缓存,首次访问,查询数据库,将数据储存到缓存中;再次访问时,直接访问缓存,减少IO、硬盘读写次数、提高效率

8.1 一级缓存

SqlSession级别缓存,同一个SqlSession发起多次同构查询,会将数据保存在一级缓存中

作用域是一个SqlSession,无法跨域

默认开启以及缓存

8.2 二级缓存

SqlSessionFactory级别缓存,同一个SqlSessionFactory构建的SqlSession发起的多次同构查询,会将数据保存在二级缓存中

只有在查询结束(释放资源)后才会进入二级缓存

在sqlSession.commit()或者sqlSession.close()之后生效

<!--配置文件中二级缓存默认开启-->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
<!--mapper中被cache标签包裹的查询语句才能进入二级缓存-->
<cache>
    <insert>...</insert>
    <delete>...</delete>
    <select>...</select>
    <update>...</update> 
</cache>

九、Druid连接池

在pom中导入依赖

<!--Druid-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

创建MyDruidDataSourceFactory

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;

public class MyDruidDataSourceFactory extends PooledDataSourceFactory {
    public MyDruidDataSourceFactory(){
        this.dataSource = new DruidDataSource();//替换数据源
    }
}

修改数据库连接参数

<!--数据库连接参数-->
<dataSource type="util.MyDruidDataSourceFactory">
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</dataSource>

十、分页插件PageHelper

10.1 概念

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

10.2 访问与下载

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

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

10.3 使用步骤

  1. 在pom中导入依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>

在配置文件中安装(mybatis-config.xml)

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

简单使用

//假设要查寻出某张表所有的数据,使用PageHelper分页
//在调用查询方法的前一步使用PageHelper插件
//第一个参数表示查第几页,第二个参数表示没有显示几条数据
PageHelper.startPage(1, 2);
List<User> userList = mapper.findAll();
//封装list到 PageInfo对象中自动分页
PageInfo<User> userPageInfo = new PageInfo<>(userList);
  • 只有在PageHelper.startPage();方法之后的第一个查询会有分页
  • 分页插件不支持带有‘for update’的查询语句
  • 分页插件不支持嵌套查询,由于嵌套结果方式会导致结果集被折叠,无法保证分页结果数量正确

十一、注解使用

当SQL语句比较简单时,可以在Dao方法上方写注解代替映射文件

//@Select @Update @Delete @Insert操作都是相同的
@Select("select id,username,password,gender,regist_time registTime from t_user where id=#{id}")
User queryUserById(Integer id);

//主键回填,写在@Insert上方
@Options(useGeneratedKeys = true,keyProperty = "id")

十二、${}和#{}

12.1 区别

  • #{}匹配的是一个占位符,相当于JDBC中的一个?,会对一些敏感的字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止SQL注入问题。
  • ${}匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接。 ${}会与其他sql进行字符串拼接,不能预防sql注入问题。(一般用于对sql片段进行拼接,比如表名和升序降序等,不能用于传值)

十三、嵌套查询

13.1 概念

嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用mybatis的语法嵌套在一起

12.2 步骤

1.从表编辑对应Dao和mapper进行单表查询

List<Employee> queryEmployeeByDeptId(@Param("dept_id") Integer dept_id);
<select id="queryEmployeeByDeptId" resultType="Employee">
    select id,name,salary
    from t_departments
    where dept_id=#{dept_id}
</select>

2.主表也进行对应的单表查询,并使用resultMap对第一个表的查询方法进行嵌套

Department queryDepartmentById(@Param("id") Integer id);
<resultMap id="department_result" type="Department">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <result column="location" property="location"></result>
    <!--employee是主表实体类中的对象属性名-->
    <!--嵌套queryEmployeeByDeptId方法查询-->
    <!--queryEmployeeByDeptId方法查询所用的字段为外键,值与主表主键字段相同,column-->
    <collection property="employee" ofType="Employee"
                select="dao.EmployeeDao.queryEmployeeByDeptId" column="id">
    </collection>
</resultMap>

<select id="queryDepartmentById" resultMap="department_result">
    select id,name,location
    from t_departments
    where id=#{id}
</select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值