Mybatis搭建与学习

Mybatis

  1. Mybatis简介

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

  2. 搭建第一个Mybatis工程
    • 第一步:创建Java Maven项目
    • 第二步:导入pom.xml坐标
    • 第三步:创建Mybatis的核心配置文件
    • 第四步:创建实体类和数据表
    • 第五步:创建实体类的映射文件
  3. Mybatis坐标

    pom.xml

    <dependencies>
    <!--mybatis的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>
        
    <!--单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
    
    <!--mysql的驱动-->    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
     
    <!--日志:记录应用程序所有的执行过程-->    
    <dependency> 
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    </dependencies>    
    
  4. 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>
        <!--数据库的配置信息,且和spring整合结束,这些配置由sping进行管理-->
     <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:mysql://localhost:3306/databasis"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
          </dataSource>
        </environment>
      </environments>
        <!--添加映射-->
        <mappers>
            <mapper resource="com/xszx/dao/UserMapper.xml"></mapper>
        </mappers>
    </configuration>
    
  5. 创建实体类和数据表

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qxX8QMZ3-1628342290653)(C:\Users\LJW\AppData\Roaming\Typora\typora-user-images\1625728881488.png)]

  6. 实体类的映射文件

    UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--映射的类的位置-->
<mapper namespace="com.xszx.dao.UserDao">
    <!--方法名和参数类型-->
    <insert id="add" parameterType="com.xszx.entity.User">
        <!--sql语句-->
        insert into user values (null,#{username},#{password});
    </insert>
    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>
    <update id="updateUser" parameterType="com.xszx.entity.User">
        update user set username=#{username},password=#{password} where id=#{id}
    </update>
    <select id="getUser" resultType="com.xszx.entity.User">
        select * from user
    </select>
    <select id="getUserById" resultType="com.xszx.entity.User">
        select * from user where id=#{id}
    </select>
</mapper>

注意事项:

namespace命名空间必须为XXXDao的全限定类名
标签中的增删改查的id必须是XXXDao中的方法名称
paraneterType标明方法中的参数类型
书写sql语句过程中,需要#{参数}替换
7. 测试
    @Test
    public void add() throws IOException {
    
    
        //读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //创建核心SqlSessionFactory工厂
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        //通过工厂类创建Sqlsession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //通过反射创建UserDao的子实现类
        UserDao userDao=sqlSession.getMapper(UserDao.class);
        User user=new User();
        user.setUsername("admin");
        user.setPassword("123456");
        userDao.add(user);
       //提交事务
        sqlSession.commit();
    }
1625730359305

参数处理

  • 参数个数为基本类型或者字符串类型,而且个数为单个的时候,传参的过程中,#{}当中可以随意书写变量

  • 参数类型为自定义对象,而且个数为单个的时候,传参过程中,#{}当中的名称必须是自定义对象中的属性(有相对应的get方法的属性)

  • 参数个数为多个的时候,解决办法:

    • 在#{}中写固定框架底层的参数名称

          <select id="login" resultType="com.xszx.entity.User" parameterType="java.lang.String">
              select * from user where username=#{param1} and password=#{param2}
          </select>
      
    • 在XXXDao的形参钱追加@Param

      User login(@Param("username") String username, @Param("password") String password);
      
    • 在传参的过程中传递自定义对象类型

      User login(User user);
      
    • 在传参过程中,传递map类型,需注意在#{}中写map集合中的key值

      User login(HashMap map);
      //UserMapper.xml中
      select * from user where username=#{
              
              username} and password=#{
              
              password}
      

返回值处理

  • 返回值为自定义对象

    User getUserById(int id);
    <select id="getUserById" resultType="com.zx.entity.User">
        select * from t_user where id = #{id}
    </select>
    
  • 返回值为对象的一个属性

    String getUsernameById(int id);
    <select id="getUsernameById" resultType="java.lang.String">
        select username from t_user where id = #{id}
    </select>
    
  • 返回值为对象中的某几个属性

    • 对象接收

      User getUsernameandAgeById1(int id);
      <select id="getUsernameandAgeById1" resultType="com.zx.entity.User">
          select id,username,age from t_user where id = #{id}
      </select>
      
    • HashMap接受

      HashMap getUsernameandAgeById(int id);
      <select id="getUsernameandAgeById" resultType="map">
          select id,username,age from t_user where id = #{id}
      </select>
      
    • DTO模式接受

      Temp getUsernameandAgeById2(int id);
      Temp getUsernameandGnameById3(int id);
      <select id="getUsernameandAgeById2" resultType="com.zx.entity.Temp">
          select username,age from t_user where id = #{id}
      </select>
      <select id="getUsernameandGnameById3" resultType="com.zx.entity.Temp">
          select u.username,g.gname from t_user u,t_group g where u.gid = g.gid and u.id = #{id}
      </select>
      
  • 多对一关联映射
    • resultType 返回单个对象的属性

    • resultMap 返回关联对象的属性

    • 属性 id 唯一标识

    • 属性 type 最终返回类型

    • 子标签:

      • id 主键

        • column 表中的字段
        • property 实体类中的属性
      • result 普通属性

        • column 表中的字段
        • property 实体类中的属性
      • association 关联映射标签

        • 属性column 表中的字段(外键)
        • 属性property 实体中的属性
        • 属性select 查询被关联的一方 命名空间.id
        • 属性 javaType 查询被关联的一方的类型

方式一:发送多次sql语句,每张表进行单独查询,通过select属性向对方映射文件中进行查询
association: 关联标签 出现在“多”方
column:数据表中的列名称
property:实体类中的属性
select: 需要指定命名空间.id去查询关联对象
javaType: 查询结束之后的返回类型

<select id="getUser04" parameterType="int" resultMap="userResult">
    select * from t_user where id = #{id}
</select>
<resultMap id="userResult" type="com.zx.entity.User">
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="age" property="age"></result>
    <association column="gid" property="group" select="com.zx.dao.GroupDao.getGroupByid" javaType="com.zx.entity.Group"></association>
</resultMap>

方式二:发送一次sql语句,进行联表查询,需要注意SQL语句的性能,不需要使用select属性

association: 关联标签 出现在“多”方
column:数据表中的列名称
property:实体类中的属性
javaType: 查询结束之后的返回类型

association打开,可以嵌入子标签:

​ id:对方表中的主键
​ column:数据表中的列名称
​ property:实体类中的属性
​ result:其他属性
​ column:数据表中的列名称
​ property:实体类中的属性

<select id="getUser05" parameterType="int" resultMap="userResult05">
    select u.id uid,u.username username,u.password password,u.age age,g.id gid,g.gname gname from t_user u,t_group g where u.gid = g.id and u.id = #{id};
</select>

<resultMap id="userResult05" type="com.zx.entity.User">
    <id column="uid" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="age" property="age"></result>
    <association column="gid" property="group" javaType="com.zx.entity.Group">
        <id column="gid" property="id"></id>
        <result column="gname" property="gname"></result>
    </association>
</resultMap>
一对多集合映射

方式一:发送多次sql语句,每张表进行单独查询,通过select属性向对方映射文件中进行查询

<select id="getGroupByid02" resultMap="groupResult02" parameterType="int">
    select * from t_group where id = #{id}
</select>
<resultMap id="groupResult02" type="com.zx.entity.Group">
    <id column="id" property="id"></id>
    <result column="gname" property="gname"></result>
    <collection column="id" property="users" select="com.zx.dao.UserDao.getUsersByGid" ofType="com.zx.entity.User" ></collection>
</resultMap>

方式二:发送一次sql语句,进行联表查询,需要注意SQL语句的性能,不需要使用select属性

collection打开,可以嵌入子标签:

​ id:对方表中的主键
​ column:数据表中的列名称
​ property:实体类中的属性
​ result:其他属性
​ column:数据表中的列名称
​ property:实体类中的属性

<select id="getGroupByid03" resultMap="groupResult03" parameterType="int">
    select g.id gid,g.gname gname,u.id uid,u.username username,u.password password,u.age age from t_user u,t_group g where u.gid = g.id and g.id = #{gid}
</select>

<resultMap id="groupResult03" type="com.zx.entity.Group">
    <id column="gid" property="id"></id>
    <result column="gname" property="gname"></result>
    <collection column="gid" property="users" ofType="com.zx.entity.User" >
        <id column="uid" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="age" property="age"></result>
    </collection>
</resultMap>
多对多集合映射
<select id="getStudentBySid" parameterType="int" resultMap="studentResult01">
    select * from t_student where sid = #{sid}
</select>
<resultMap id="studentResult01" type="com.zx.entity.Student">
    <id column="sid" property="sid"></id>
    <result column="sname" property="sname"></result>
    <collection column="sid" property="teachers" select="com.zx.dao.TeacherDao.getTeacherByTid" ofType="com.zx.entity.Teacher"></collection>
</resultMap>

<select id="getTeacherBySid" parameterType="int" resultType="com.zx.entity.Teacher">
    select * from t_teacher where tid in (select tid from t_student_teacher where sid = #{sid})
</select>
<select id="getTeacherByTid" parameterType="int" resultMap="teacherResult">
    select t.tid tid,t.tname tname,s.sid sid,s.sname sname from
    t_teacher t left join t_student_teacher st on t.tid = st.tid
    left join t_student s on st.sid = s.sid
    where t.tid = #{tid}
</select>
<resultMap id="teacherResult" type="com.zx.entity.Teacher">
    <id column="tid" property="tid"></id>
    <result column="tname" property="tname"></result>
    <collection column="tid" property="students" ofType="com.zx.entity.Student">
        <id column="sid" property="sid"></id>
        <result column="sname" property="sname"></result>
    </collection>
</resultMap>
缓存机制

一级缓存 SqlSession缓存 (默认开启)

二级缓存 SqlSessionFactory缓存

​ 手动开启二级缓存

  • 第一步:在映射文件中追加二级缓存配置
<!--开启本mapper的namespace下的二级缓存-->
    <!--
        eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
        (1) LRU,最近最少使用的,一处最长时间不用的对象
        (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
        (3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
        (4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
                移除最长时间不用的对形象

        flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
        SQL被执行的时候才会去刷新缓存。

        size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
        这里配置的是1024个对象

        readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
        办法修改缓存,他的默认值是false,不允许我们修改
    -->
    <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
  • 第二步:在mybatis中的配置文件中开启二级缓存开关

    <settings>
            <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
            <setting name="cacheEnabled" value="true" />
            .....
        </settings>
    注意事项:在新版本中默认不需要在这里开启
    
  • 第三步:如果某些方法不想使用二级缓存,在方法中的select标签中可以设置关闭二级缓存

    <select id="getUsers" resultType="com.zx.entity.User" useCache="false">
    
抓取策略
fetchType
      lazy 懒加载
      eager 及时加载

从一方查询多方的时候,需要考虑多方的数据量

如果只是使用一方的数据,而不使用多方数据的情况下,在执行过程中不需要发送查询多方的sql语句,需要配置抓取策略为 懒加载

在配置好懒加载的前提下,使用一方数据结束,马上关闭sqlSession之后,想要使用多方数据,在mybatis中可以正常执行

在未来的Hibernate或者SpringDataJPA中,执行上述步骤要报错 no session

猜你喜欢

转载自blog.csdn.net/qq_45299673/article/details/119492947