Mybatis

目录

1、简介

2、第一个MyBatis程序

3、CRUD⭐

4.映射器 (mappers)三种方式

5、解决属性名和字段名不一致的问题

6、分页

7、使用注解开发⭐

 8.Lombok(贼好用 一个注解 解放实体类)

9、多对一处理

10、一对多处理

11、动态SQL

12、缓存


1、简介

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

1.2、为什么要用MyBatis?
帮助开发者更方便的将数据存入数据库中。

简化JDBC的代码,自动化。

简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。

解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

提供映射标签,支持对象与数据库的orm字段关系映射

提供对象关系映射标签,支持对象关系组建维护

提供xml标签,支持编写动态sql。

最重要的一点:使用的人多!

Spring SpringMVC SpringBoot

2、第一个MyBatis程序

2.1、编写mybatis的核心配置文件
<?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>
    <environments default="development">
        <environment id="development">
            <!--transactionManager事务管理器,JDBC|MANAGED|自定义,-->
            <!--JDBC:使用了JDBC的提交和回滚设置-->
            <!--MANAGED:不提交或回滚一个连接,让容器来管理事务的整个生命周期-->
            <transactionManager type="JDBC"/>
            <!--dataSource数据源,UNPOOLED|POOLED|JNDI|自定义-->
            <!--UNPOOLED:不使用连接池-->
            <!--POOLED:使用连接池-->
            <!--JNDI: 在EJB 或应用服务器这类容器中查找指定的数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
2.2、编写mybatis工具类
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //官方文件硬性要求的写法
            //使用Mybatis f获取SqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory 我们可以从中获得 SqlSessionFactory 实例
    //SqlSessionFactory 完全包含了面向数据库 执行SQL 的所有方法
    //sqlSession== Connection
    
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

2.3、编写代码

1.实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

2.Dao接口

public interface UserDao {
    /**
     * 获取用户
     *
     * @return
     */
    List<User> getUserList();
}

3.接口实现类 由原来的UserDaoImpl转变为一个 Mapper配置文件

<?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接口-->
<mapper namespace="com.yt.dao.UserDao">
    <!--select查询语句-->
    <select id="getUserList" resultType="com.yt.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

4.junit测试

@Test
public void test(){
    //第一步:获得SqlSession对象SqlSession
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一(推荐)
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    List<User> userList = mapper.getUserList();

    //方式二 (不推荐)
//        List<User> userList = sqlSession.selectList("com.yt.dao.UserDao.getUserList");


    for (User user : userList) {
        System.out.println("user = " + user);
    }
    sqlSession.close();
}

3、CRUD⭐


步骤 (核心)
选择查询语句

id : 对应的namesspace中的方法名
resultType :sql语句执行的返回值
parameterType : 参数类型
编写接口
编写对应的mapper中的sql语句
测试

3.1、select
/**
 * 查询全部用户
 *
 * @return
 */
List<User> getUserList();
<select id="getUserList" resultType="com.yt.pojo.User">
    select * from mybatis.user
</select>
@Test
public void test(){
    //第一步:获得SqlSession对象SqlSession
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一(推荐)
    UserDao mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUserList();
    for (User user : userList) {
        System.out.println("user = " + user);
    }
    sqlSession.close();
}
3.2、Insert
<insert id="addUser" parameterType="com.yt.pojo.User">
    insert into mybatis.user (id, name, pwd)
    values (#{id}, #{name}, #{pwd});
</insert>
3.3、update
<update id="updateUser" parameterType="com.yt.pojo.User">
    update mybatis.user
    set name=#{name},
        pwd=#{pwd}
    where id = #{id};
</update>
3.4、Delete
<delete id="deleteUser" parameterType="int">
    delete
    from mybatis.user
    where id = #{id};
</delete>
3.5、万能Map
假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map或者注解!
<insert id="addUser2" parameterType="map" >
    insert into mybatis.user (id, name, pwd)
    values (#{userid}, #{username}, #{password});
</insert>

 3.6、SQL注入注意

模糊查询
List<User> userList = mapper.getUserLike("%李%");
select * from mybatis.user where name like "%"#{value}"%"
4、配置解析
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)  
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
<!--        是否开启自动驼峰命名规则映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
<!--        类型别名 扫描实体类的包 可以直接写类名 他的默认别名就是在这个包的首字母小写类名-->
        <package name="com.hzh.pojo"/>
    </typeAliases>


    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

<!--类的方式可以读取接口 包的方式是扫描整个包 资源的方式的读取该路径下的xml文件(注意resource之间用"/",而class和package用".")-->
<!--    class 和 package 可以使注解和mapper.xml两种方式同时生效-->
<!--    class 和 package要求:接口和他的Mapper配置文件必须同名且在同一个包下-->
<!--    必须在同一个包下(或者接口在java下的com.hzh.dao, 但在resource下也建立相同的com.hzh.dao,此时也相当于同一个包下)-->
<!--    resource没有要求,但resource不行 只能读取xml配置文件-->
 <mappers >
<!--     <mapper resource="com/hzh/dao/TeacherMapper.xml"/>-->
     <package name="com.hzh.dao"/>
<!--     <mapper class="com.hzh.dao.TeacherMapper"/>-->
<!--     <mapper class="com.hzh.dao.StudentMapper"/>-->
    </mappers>
</configuration>

注意点:

1.属性可以引用配置文件,也可以直接在 <property name 中书写,也可以两种方法都用

2.类型别名可以为 Java 类型设置一个短的名字,也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

 <typeAliases>
<!--        类型别名 扫描实体类的包 可以直接写类名 他的默认别名就是在这个包的首字母小写类名-->
        <package name="com.hzh.pojo"/>
    </typeAliases>
 

3.一些重要的设置 

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

<!--        是否开启自动驼峰命名规则映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

  <setting name="logImpl" value="STDOUT_LOGGING"/>

4.映射器 (mappers)三种方式

<mappers>
 <mapper resource="com/hzh/dao/TeacherMapper.xml"/>
    <package name="com.hzh.dao"/>
    <mapper class="com.hzh.dao.TeacherMapper"/>
</mappers>

区别:

<!--类的方式可以读取接口 包的方式是扫描整个包 资源的方式的读取该路径下的xml文件(注意resource之间用"/",而class和package用".")-->
<!--    class 和 package 可以使注解和mapper.xml两种方式同时生效-->
<!--    class 和 package要求:接口和他的Mapper配置文件必须同名且在同一个包下-->
<!--    必须在同一个包下(或者接口在java下的com.hzh.dao, 但在resource下也建立相同的com.hzh.dao,此时也相当于同一个包下)-->
<!--    resource没有要求,但resource不行 只能读取xml配置文件-->

5、解决属性名和字段名不一致的问题

1、起别名 

2、resultMap (重点)⭐

id   name   pwd
id   name   password
<!--结果集映射-->
<resultMap id="UserMap" type="user">
    <!--column数据库中的字段,property实体类中的属性-->
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultMap="UserMap">
    select *
    from mybatis.user
</select>

6、分页

1.接口

/**
 * 分页查询
 * @param map
 * @return
 */
List<User> getUserByLimit(Map<String,Integer> map);

2.Mapper.xml

<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
    select *
    from mybatis.user limit #{startIndex},#{pageSize}
</select>

3.测试

@Test
public void getUsersByLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex",0);
    map.put("pageSize",3);
    List<User> usersByLimit = mapper.getUserByLimit(map);
    for (User user : usersByLimit) {
        System.out.println(user);
    }
    sqlSession.close();
}

7、使用注解开发⭐

/**
 * 查询全部用户
 * @return
 */
@Select("select * from user")
List<User> getUsers();

7.1、CRUD自动提交

我们可以在工具类创建的时候实现自动提交事务!
public static SqlSession getSqlSession() {
    return sqlSessionFactory.openSession(true);
}

7.2、crud注解

package com.yt.dao;

import com.yt.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;

/**
 * ClassName:UserMapper
 * Package:com.yt.dao
 * Description:
 *
 * @date:2021/7/19 15:05
 * @author:yt
 */

public interface UserMapper {

    /**
     * 查询全部用户
     *
     * @return
     */
    @Select("select * from user")
    List<User> getUsers();
    // 方法存在多个参数,所有的参数前面必须加上 @Param注解

    /**
     * 按照id查询用户
     *
     * @param id
     * @return
     */
    @Select("select * from user where id = #{id}")
    User getUserByID(@Param("id") int id);

    /**
     * 添加用户
     *
     * @param user
     * @return
     */
    @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
    int addUser(User user);

    /**
     * 修改用户
     *
     * @param user
     * @return
     */
    @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
    int updateUser(User user);

    /**
     * 删除用户
     *
     * @param id
     * @return
     */
    @Delete("delete from user where id = #{uid}")
    int deleteUser(@Param("uid") int id);
}

7.3关于@Param() 注解

 @Select("select * from user where id = #{id} and name = #{nam}")
        // 方法存在多个参数,所有的参数前面必须加上 @Param注解 此时起作用的是param里面的参数
    User getUserByID(@Param("id") int id,@Param("nam") String name);

  基本类型的参数或者String类型,需要加上 引用类型不需要加 如果只有一个基本类型的话,可以忽略,但是建议大家都加上! 我们在SQL中引用的就是我们这里的 @Param() 中设定的属性名!

 7.4#{} ${} 区别

在MyBatis中提供了两种方式读取参数的内容到SQL语句中,分别是 #{参数名} :实体类对象或则Map集合读取内容 ${参数名} :实体类对象或则Map集合读取内容 #{} : 采用预编译方式,可以防止SQL注入 ${}: 采用直接赋值方式,无法阻止SQL注入攻击 在大多数情况下,我们都是采用#{}读取参数内容.但是在一些特殊的情况下,我们还是需要使用${}读取参数的.

 8.Lombok(贼好用 一个注解 解放实体类)

8.1导入jar包

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

8.2常用的Lombok注解

@Data:无参构造(没有有参构造),get、set、tostring、hashcode,equals
@AllArgsConstructor 有参构造
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@Getter

9、多对一处理

9.1 实体类Student

@Data
public class Student {
    private int id;
    private String name;
    private Teacher teacher;//多个学生关联一个老师
}

9.2接口配置

public interface StudentMapper {

    List<Student> getStudent();

    List<Student> getStudent2();
}

9.3两种Mapper.xml配置方法

<mapper  namespace="com.hzh.dao.StudentMapper">
    <!--方式二  按照结果嵌套处理-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.id tid,t.name tname
        from student s ,teacher t
        where s.tid = t.id;
    </select>
<!--结果集映射-->
    <resultMap id="StudentTeacher2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
    </association>
</resultMap>


    <!--方式一  按照查询嵌套处理 -->
    <!--
    思路:1. 查询所有的学生
         2. 根据查询出来的tid 寻找对应的老师
  -->
    <resultMap id="StudentTeacher" type="student">
        <id column="id"  property="id" />
        <result column="name"  property="name" />
        <!--复杂的属性与要单独处理 对象 association  集合 collection-->
<!--        javaType="" 指定的属性的类型用javaType-->
        <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    </resultMap>

    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>
    <select id="getTeacher" resultType="teacher">
        select * from teacher where id = #{tid}
    </select>
</mapper>

10、一对多处理

10.1 实体类Teacher

@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;//一个老师拥有多个学生
}

10.2 接口配置

public interface TeacherMapper {
    @Select("Select * from teacher")
    List<Teacher> getTeacher();//不做Teacher结果集映射,查询出的students集合为null

    Teacher getTeacherByID(@Param("tid") int id);//查询指定id的老师及其所有学生的信息
    //返回值是teacher 但返回private List<Student> students属性; Students集合


}

10.3 两种xml配置方法

<mapper  namespace="com.hzh.dao.TeacherMapper">
<!--  推荐使用 比子查询清晰
  按照结果嵌套处理-->
    <select id="getTeacherByID" resultMap="TeacherStudents">
        select s.id sid, s.name sname, t.name tname, t.id tid
        from student s,
             teacher t
        where s.tid = t.id and t.id = #{tid}
    </select>
<!--Teacher结果集映射(因为实体内中Teacher字段和查询结果的表中字段不一致)-->
    <resultMap id="TeacherStudents" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--复杂的属性与要单独处理 对象 association  集合 collection-->
        <!--
       javaType="" 指定的实体类中属性的类型用 javaType获取
       ofType="" 指定的集合中的泛型类型用 ofType 获取
   -->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
</mapper>

 小结:

1.关联 - association 【多对一】

2.集合 - collection 【一对多】

3.javaType & ofType

JavaType 用来指定实体类中属性的类型

ofType 用来指定映射到List或者集合中的 pojo类型,泛型中的约束类型!

注意点: 保证SQL的可读性,尽量保证通俗易懂 注意一对多和多对一中,属性名和字段的问题! 如果问题不好排查错误,可以使用日志 , 建议使用 Log4j

11、动态SQL

什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句

11.1、常用标签

1.if(用来逻辑判断)
2.choose (when, otherwise)
3.trim (where, set) (这三个都用来优化SQL )
4.foreach
<!--通过if test=""标签附加-->
    <select id="QueryBlogIF" parameterType="map" resultType="blog">
--         where 1=1 不正规   使用where标签解决sql拼接问题-
-- where元素只会在至少有一个子元素的条件返回sql子句的情况下才会插入'where',若语句的开头是"AND"或者"OR",where 元素也会自动去除他们
        select * from mybatis.blog
        <where>
       <if test="title !=null">
           title = #{title}
         </if>
        <if test="author !=null">
            and author = #{author}
        </if>
        </where>
</select>

<!--    choose (when, otherwise) 从多个条件中选择一个使用-->
    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select *
        from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    AND title like "%"#{title}"%"
                </when>
                <when test="author != null ">
                    AND author = #{author}
                </when>
                <otherwise>
                    AND views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>

<!--    set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。-->
    <update id="updateBlog" parameterType="map" >
        update mybatis.blog
        <set>
            <if test="title!=null">
                title=#{title},
            </if>
            <if test="author!=null">
                author=#{author},
            </if>
        </set>
        where id=#{id}
    </update>

    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>
    
</mapper>

11.2、SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便复用!

1.使用SQL标签抽取公共的部分

<sql id="if-title-author">
    <if test="title!=null">
        title=#{title},
    </if>
    <if test="author!=null">
        author=#{author},
    </if>
</sql>
2.在需要使用的地方使用Include标签引用即可
<update id="updateBlog" parameterType="map" >
    update mybatis.blog
    <set>
        <include refid="if-title-author"></include>
    </set>
    where id=#{id}
</update>

11.3 Foreach

    List<Blog> queryBlogForeach(Map map);//foreach遍历id集合,查询第1~3号记录的博客
    //也可以参数直接传入List list 不用在map中存放list 但我觉得用万能map可以提高可用性 除了list集合 还可以存放其他类型

 <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

12、缓存

12.1 工作机制

一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
新的会话查询信息,就可以从二级缓存中获取内容;
不同的mapper查出的数据会放在自己对应的缓存(map)中;
12.2 小结

只要开启了二级缓存,在同一个Mapper下就有效
所有的数据都会先放在一级缓存中;
只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!

12.3 缓存原理

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值