关于MyBatis的一些总结


概述

MyBbatis它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低。

ORM是什么?

Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的User类,去对应数据库中的一张user表,类中的属性和表中的列一一对应。

mybatis为什么是半自动的ORM框架?

以为使用mybatis开发的时候,需要手写sql语句,而其他全自动的ORM框架,则不需要手写sql语句。更因为mybatis需要手写sql语句,拥有更好的灵活性。与传统的JDBC相比,mybatis提供了输入和输出映射,可以很方便地进行SQL设置,以及结果集的封装。并且还提供了关联查询动态SQL等功能,极大地提升了开发的效率。

快速开发

步骤

  1. 编写全局配置文件
  2. 编写mapper映射文件
  3. 加载全局配置文件,生成SqlSessionFactory
  4. 创建SqlSession,调用mapper映射文件中的SQL语句来执行CRUD操作

具体操作

1. 在IDEA中新建一个maven的项目

2. 在项目的porn.xml配置中导入相关依赖,例:

<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
          <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.12</version>
            </dependency>
            <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

3. 创建mybatis-config.xml全局配置文件

<?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"/>
    </settings>
    <environments default="development">
        <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>
    </environments>
    <!--绑定接口-->
    <mappers>
    <!-- <mapper resource="com/weirdo/dao/AuthorMapper.xml"/>-->
      <mapper class="com.weirdo.dao.AuthorMapper"/>
    </mappers>
</configuration>

4. 配置数据库连接文件db.properties

driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&userUnicode=true&acharacterEncoding=UTF-8
username=root
password=root

5. 编写Utils工具类

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //使用mybatis获取sqlsessionfactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory  = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
public static SqlSession getSqlSession() {
    return sqlSessionFactory.openSession(true);//此处true可以自动提交事务
}

}

7. 创建实体类

public class User {
    private int id;
    private String name;
    private String pwd;
}

8. 编写mapper映射文件(Mapper.xml)

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper-->
              <!--此处必须是.不能是/-->
<mapper namespace="com.dao.UserMapper">
    <!--模糊查询-->
    <select id="getUserLike" resultType="com.pojo.User">
        select * from mybatis.user where name like #{value}
    </select>
    <!--查询语句-->
    <select id="getUserList" resultType="com.pojo.User">
        select * from mybatis.user
    </select>
    <select id="getUserById" parameterType="int" resultType="com.pojo.User">
        select * from mybatis.user where id = #{id}
    </select>
    <insert id="addUser" parameterType="com.pojo.User">
        insert  into mybatis.user (id,name,pwd) value (#{id},#{name},#{pwd})
    </insert>
    <update id="updateUser" parameterType="com.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id =#{id}
    </update>
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>
</mapper>

9. 编写测试类

public class UserDaoTest {
//模糊查询
    @Test
    public void getUserLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserLike("%李%");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    //查询全部用户
    @Test
    public void test(){
        //第一步,获得sqlsession对象
        SqlSession sqlSession= MybatisUtils.getSqlSession();
        //执行sql 方式一 getMapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        //方式二
        //List<User> userList=sqlSession.selectList("com.dao.UserDao.getUserList");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    //根据id查询用户
    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        sqlSession.close();
    }
    //增删改需要提交事务
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.addUser(new User(9, "小李", "1233"));
        if(res>0){
            System.out.println("插入成功");
        }
        sqlSession.commit();//提交事务很重要
        sqlSession.close();
    }
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(2,"小王","1115"));
       sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(5);
         sqlSession.commit()
        sqlSession.close();
    }
}

一些注意问题(和解决方法)

  1. 在项目中导入相关依赖后,仍然报错,则需要刷新maven仓库中的项目依赖
  2. 全局配置文件中的标签是有顺序的
<configuration>
	<!-- 配置顺序如下
     properties  

     settings

     typeAliases

     typeHandlers

     objectFactory

     plugins

     environments
        environment
            transactionManager
            dataSource
            
     mappers
     -->
</configuration>

  1. mappers标签引入映射器的俩种方式(常用)
<!--通过resource属性引入classpath路径的相对资源-->
<mappers>
  <mapper resource="com/weirdo/dao/AuthorMapper.xml"/>
</mappers>
<!--通过class属性指定mapper接口名称,此时对应的映射文件必须与接口位于同一路径下,并且名称相同-->
<mappers>
  <mapper class="com.weirdo.dao.AuthorMapper"/>
</mappers>
  1. mapper.xml中增删改需要提交事务,在测试类中添加
sqlSession.commit();

也可以在工具类中设置(默认为flase,改为true即为自动提交)

public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);//此处true可以自动提交事务
    }
  1. mapper.xml的SQL语句中的占位符 ${ } 和 #{ }

一般会采用#{},#{}输入参数的占位符,相当于jdbc的?,防注入 ,自动添加了‘ ’ 引号!
而${},一般会用在模糊查询的情景,比如

SELECT * FROM student WHERE name like '%${name}%';
  1. 关于resultType和parameterType区别

resultType:返回值类型,类型即为对象类型,返回结果字段与对象属性匹配映射,类型中的属性名要与查询条件保持一致,否则就会失败。
parameterType:接收参数类型,同为对象类型,单字段 例如String类型 可以使用全包名或者单名称。

基于XML代理开发

全局配置文件和mapper.xml文件是最基本的配置,在完成基本配置后,我们可以不需要创建dao类,而可以直接创建一个mapper接口,进行处理。

  1. 创建接口
public interface UserMapper {
    //查询全部用户
    List<User> getUserList();
    //根据id查询用户
    User getUserById(int id);
    //添加用户
    int addUser(User user);
    //修改用户
    int updateUser(User user);
    //删除用户
    int deleteUser(int id);
}
  1. 创建mapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper-->
<!--此处必须是.不能是/-->
<mapper namespace="com.dao.UserMapper">
    <!--查询语句-->
    <select id="getUserList" resultType="User">
        select * from mybatis.user
    </select>
    <select id="getUserById" parameterType="int" resultType="com.pojo.User">
        select * from mybatis.user where id = #{id}
    </select>
    <insert id="addUser" parameterType="com.pojo.User">
        insert  into mybatis.user (id,name,pwd) value (#{id},#{name},#{pwd})
    </insert>
    <update id="updateUser" parameterType="com.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id =#{id}
    </update>
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>
</mapper>
  1. 测试类
public class UserDaoTest { 
    @Test
    public void test(){
        SqlSession sqlSession= MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        //方式二 List<User> userList=sqlSession.selectList("com.dao.UserDao.getUserList");
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        sqlSession.close();
    }
    //增删改需要提交事务
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int res = mapper.addUser(new User(9, "小李", "1233"));
        if(res>0){
            System.out.println("插入成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(2,"小王","1115"));
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(5);
        sqlSession.commit();
        sqlSession.close();
    }
}

基于xml代理开发的注意事项

mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来

  • mapper接口的全限定名,要和mapper.xml的namespace属性一致
  • mapper接口中的方法名要和mapper.xml中的SQL标签的id一致
  • mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  • mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致

基于注解代理开发

如果对xml配置文件感到麻烦,则可以考虑使用注解的开发方式,不过注解的开发方式,会将SQL语句写到代码文件中,后续的维护性和扩展性不是很好(如果想修改SQL语句,就得改代码,得重新打包部署,而如果用xml方式,则只需要修改xml,用新的xml取替换旧的xml即可)。

使用注解的开发方式,也还是得有一个全局配置的xml文件,不过mapper.xml就可以省掉了,具体操作只用2步,如下

  1. 创建一个mapper接口
public interface UserMapper {
   @Select("select * from user")
   List<User> getUsers();
   //方法存在多个参数,所有参数前面必须加上@Param("id")注解
   @Select("select * from user where id = #{id}")
   User getUserById(@Param("id") int id);
   @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})")
   int addUser(User user);
   @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
   int updateUser(User user);
   @Delete("delete from user where id=#{id} ")
   int deleteUser(@Param("id") int id);
}
  1. 在全局配置文件中修改mappers标签,指定到mapper接口处
    <mappers>
        <mapper class="com.weirdo.dao.UserMapper"/>
    </mappers>
  1. 测试类
public class UserMapperTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        List<User> users = mapper.getUsers();
//        for (User user : users) {
//            System.out.println(user);
//        }

//        User userById = mapper.getUserById(1);
//        System.out.println(userById);

//        mapper.addUser(new User(10,"张德胜","123432"));

//        mapper.updateUser(new User(6,"李佳怡","0988"));

        mapper.deleteUser(5);
        sqlSession.close();
    }
}

基于注解代理开发的注意事项

  1. 当使用注解开发时,若需要传入多个参数,可以结合@Param注解
  2. @Param标签会被mybatis处理并封装成一个Map对象,比如上面的示例中,实际传入的参数是一个Map对象,@Param标签帮忙向Map中设置了值
  3. 在文章的上面,介绍了俩种mappers标签映入映射器的方式,在此处做一个细致的探讨补充
<!--在mapper接口中使用注解开发-->
<mappers>
  <mapper resource="com/weirdo/dao/AuthorMapper.xml"/>
</mappers>
<!-- 普通加载xml -->
<mappers>
  <mapper class="com.weirdo.dao.AuthorMapper"/>
</mappers>

而在实际工作中,一般我们会将一张表的SQL操作封装在一个mapper.xml中,可能有许多张表需要操作,那么我们是不是要在<mappers>标签下写多个<mapper>标签呢?其实不用,还有第三种加载mapper的方法,使用<package> 标签

<mappers>
    <package name="com.weirdo.mapper"/>
</mappers>

这样就会自动加载com.weirdo.mapper包下的所有mapper,这种方式需要将mapper接口文件和mapper.xml文件都放在com.weirdo.mapper包下,且接口文件和xml文件的文件名要一致。

  1. 关于target工程目录下需要添加以下配置
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

mappers标签里映射的时候会出现找不到mapper的情况。这是因为src/main/java源码目录下的文件,maven打包时只会将该目录下的java文件打包,而其他类型的文件都不会被打包进去。需要在porn.xml的添加相关配置才可以。

动态SQL

可以根据具体的参数条件,来对SQL语句进行动态拼接。

比如在开发中,由于不确定查询参数是否存在,会使用类似于where 1 = 1来作为前缀,然后后面用AND 拼接要查询的参数,这样,就算要查询的参数为空,也能够正确执行查询,如果不加1 = 1,则如果查询参数为空,SQL语句就会变成SELECT * FROM student where,SQL不合法。

mybatis里的动态标签主要有

  • if
<select id="queryBlogIF" parameterType="map" resultType="blog">
       select * from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
    </select>
  • choose,when,oherwise
<!-- choose 和 when , otherwise 是配套标签 
类似于java中的switch,只会选中满足条件的一个
-->
 <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
           <choose>
               <when test="title != null">
                   title = #{title}
               </when>
               <when test="author != null">
                  and author = #{author}
               </when>
               <otherwise>
                   and views=#{views}
               </otherwise>
           </choose>
        </where>
    </select>
  • trim、where、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>

SQL片段

有些时候可以用sql便签抽取公共部分,在使用的地方使用include标签

要注意:

  • 最好是单表
  • sql里不要有where标签
<sql id="if-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>
<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <include refid="if-title-author"></include>
    </where>
</select>
  • foreach
<!--ids是传的,#{id}是遍历的-->
<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>

测试类

@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    ArrayList<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(3);
    map.put("ids",ids);

    List<Blog> list = blogMapper.queryBlogForeach(map);

    for (Blog blog : list) {
        System.out.println(blog);
    }

    sqlSession.close();
}

关于缓存

一级缓存

默认开启状态,同一个SqlSession级别共享的缓存,在一个SqlSession的生命周期内,执行俩次SQL查询,当然第二次查询会直接查询缓存,而不是数据库。
但如果,第一次和第二次相同的SQL查询之间,执行了INSERT/UPDATE/DELETE这种DML操作,一级缓存会被清空,第二次会查询数据库

缓存失效

  • 同一个SqlSession下执行增删改操作,不用提交,会清空一级缓存
  • SqlSession提交或关闭的时候,会清除一级缓存
  • 在全局配置文件中设置<setting name="localCacheScope" value="STATEMENT"/> 这样会使一级缓存失效,二级缓存并不受影响
  • 对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement

二级缓存

二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQL session,默认关闭,在mybatis-config.xml文件中的标签配置开启缓存<settings name="cacheEnabled" value="true"/>开启二级缓存总开关,然后在某个具体的mapper.xml中增加<cache />,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交,查询的数据才会被刷新到二级缓存当中

association和collection的区别

简单理解就是,association是用于一对一和多对一关系
collection是用于一对多关系

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>