MyBatis入门

    技术2026-03-20  22

    文章目录

    MyBatis入门什么是MyBatis获取MyBatis第一个MyBatis程序搭建环境:创建模块:编写配置文件编写MyBatis工具类编写实体类User:编写 Mapper接口 和 xml注册mapper测试 核心API注意事项:SqlSessionFactoryBuilderSqlSessionFactorySqlSession CRUDselectisnertupdatedelete 配置解析环境(environments)属性(properties):别名(typeAliases)设置映射器方式一:使用资源路径方式二:使用接口全限定名方式三:使用包的方式 ResultMap 结果集映射取别名:结果集映射: 注解开发CURD解决多参数问题#{} 和 ${} 的区别 复杂语句查询:表和POJO多对一:association一对多:collection 动态SQL缓存简介MyBatis缓存一级缓存缓存失效的情况: 二级缓存:工作机制核心配置文件mapper.xml

    MyBatis入门

    什么是MyBatis

    持久层框架。避免JDBC代码 :无设置动态参数 和 处理结果集的getXXX方法。配置:使用xml和注解 配置原生类型,接口 和 Java的POJO为数据库中的记录。sql代码写在xml文件当中,完成分离。

    获取MyBatis

    Maven仓库GitHub中文文档

    第一个MyBatis程序

    搭建环境:

    创建数据库。新建项目 : 2.1 : 创建一个空的maven项目, 无需使用骨架。 2.2 : 删除src目录。导入依赖 : mybatis + mysql 驱动 + Junit。 <!-- 依赖 --> <dependencies> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- myBatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!-- Junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>

    创建模块:

         特意说明,这里使用模块儿而不是整个项目是为了方便学习。每个模块儿的pom.xml都在父级项目当中进行了声明,这样不用频繁进行jar包的导入。

    编写配置文件

        在src/main/resouces目录下面创建一个xml文件,建议使用`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> <!-- 可以配置多套环境 --> <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/mybatis?userSSL=true&amp;userUnicode=ture&amp;characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> </configuration>

    编写MyBatis工具类

        目的是为了将MyBatis配置文件加载,其他内容进行一次封装。

    public class MyBatisUtil { // 加载配置文件获取工厂 private static SqlSessionFactory sqlSessionFactory = null; static { String resource = "mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } finally { if(inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } }

    编写实体类User:

        这里的user属性 和 数据库mybits.user中的字段是一样(先保持名字一致)。

    public class User { private int id; private String name; private String pwd; // 省略构造 + getter/setter }

    编写 Mapper接口 和 xml

    Mapper接口 package dao; import pojo.User; import java.util.List; public interface UserMapper { List<User> getAllUser(); } 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 : 指定到绑定到Mapper接口。 --> <mapper namespace="dao.UserDao"> <!-- id : 对应Mapper接口的方法名字. resultType : 返回的Pojo类型 --> <select id="getAllUser" resultType="pojo.User"> select * from mybatis.user; </select> </mapper>

    注册mapper

    <mappers> <mapper resource="dao/UserMapper.xml"></mapper> </mappers>

    测试

    public class UserDaoTest { @Test public void test() { //1. 获得SQLSession对象 SqlSession session = MyBatisUtil.getSqlSession(); //2. UserMapper mapper = session.getMapper(UserMapper.class); List<User> userList = mapper.getAllUser(); System.out.println(userList); } }

    核心API注意事项:

    SqlSessionFactoryBuilder

             一旦创建了SqlSessionFactory就不再需要了,因此其最佳使用位置是局部方法位置。不应该让其一直存在,以保证所有的XML解析资源可以被释放给重要的事情。

    SqlSessionFactory

            被创建就应该一直存在,没有必要抛弃它后重新创建。其最佳作用域是应用的作用区域。很多方法可以做到,比如单例模式,静态单例模式,或者用静态代码块儿进行初始化。

    SqlSession

            SqlSession是线程不安全,放在局部作用区域使用,确保其在单线程中。应该让每次收到一个请求,打开一个SqlSession,返回响应,然后关闭。

    CRUD

    select

    <!-- id : 对应的接口当中的方法名。 resultType : SQL 语句执行的返回值。 parameterType : 参数的类型。 --> <! -- 需求:根据指定的id查询用户。 UserMapper中存在抽象方法 : User getUserById(int id); --> <select id="getUserById" resultType="pojo..User" paramterType="int" > select * from user where id = #{id} </select>

    isnert

    <!-- 需求: 插入一个User 在UserMapper中存在抽象方法:insertUser(User user); insert 没有resultType 参数对象的属性可以直接在sql中使用,不用get方法 --> <isnert id="insertUser" paramterType="pojo.User"> insert into user (id, name, pwd) values (NULL, #{name}, #{pwd}); </isnert> 测试代码 @Test public void insertUser() { User user = new User(-1, "张三", "xxxxxx"); SqlSession session = MyBatisUtil.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); mapper.insertUser(user); // 提交事务 session.commit(); session.close(); }

    update

    <!-- UserMapper中存在抽象方法:int updateUser(User user); --> <update id="updateUser" paramterType="pojo.User"> update user set name= #{name} where id=#{id}; </update> 测试代码 @Test public void updateUser() { SqlSession session = MyBatisUtil.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); User user = new User(3, "王五", null); mapper.updateUser(user); // 提交事务 session.commit(); session.close(); }

    delete

    <!-- UserMapper当中存在方法:int deleteUser(User user); --> <delete id="deleteUserById" paramterType="int"> delete from user where id=#{id} </delete> 测试代码 @Test public void updateUser() { SqlSession session = MyBatisUtil.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); User user = new User(3, "王五", null); mapper.updateUser(user); // 提交事务 session.commit(); session.close(); }

    配置解析

    环境(environments)

        可以配置多个环境变量对应于不同的数据库,但是项目只能使用一个数据一个环境。记住2点:MyBatis默认使用的事物管理器就是JDBC,链接池是POOLED。

    属性(properties):

        可以用来引入外部的配置文件, 或者将配置字段值当作子标签值。

    引入外部配置:

    在mybatis-config.xml直接设置配置:

    别名(typeAliases)

        类型别名是为Java类设置的一个短的名字。只和XML配置有关,存在的意义仅仅是为了减少类完全限定名的冗余。例如:

    设置

        此配置选项实在太多了,需要对照对照官网使用 ,但是先记住如下几个的使用:

    ​ 官网地址:settings设置

    <!-- 设置 --> <settings> <!-- 开启二级缓存,虽然默认是开启的,但是再开启一遍。 --> <setting name="cacheEnabled" value="true"/> <!-- 设置日志 --> <setting name="logImpl" value="LOG4J"/> </settings>

    映射器

        注册绑定我们的mapper文件。

    方式一:使用资源路径

        mapper.xml 可以放置在任何位置,资源路径写对了即可。

    <mappers> <mapper resources="dao/UserMapper.xml"/> </mappers>

    方式二:使用接口全限定名

         接口名称必须和xml文件名一致,且放在同一个目录下。

    <!-- dao 目录下 : UserMapper.java UserMapper.xml --> <mappers> <mapper class="dao.UserMapper"/> </mappers>

    方式三:使用包的方式

        可以将一个包下面的所有mapper直接进行注册,条件和方式二一致。

    <mappers> <mapper name="dao"/> </mappers>

    ResultMap 结果集映射

        为了解决了数据库记录 向 POJO的映射过程中,由于名称不一致导致的查询为null的情况,可以使用如下的解决方案:

    取别名:

        利用Sql的取别名即可了, 将查询出来的字段设置为

    结果集映射:

    <!-- UserMapper.xml --> <resultMap id="UserMap" type="User"> <!-- 什么不一样写什么 --> <result column="pwd" propertype="password"/> </resultMap> <select id="getUserById" resultMap="UserMap"> select * from user where id=#{id} </select>

    注解开发

            了解一些,主要使用的还是配置文件的方式进行开发。在注解开发当中可以不用使用mapper.xml文件了, 且mybatis-config.xml文件映射mapper的方式为导class属性的方式。

            使用注解映射简单语句比较简便,但是对于负责,需要配置结果集映射的情况,就力不从心了。

            其本质是反射机制,底层使用的动态代理。

    CURD

    public interface UserMapper { @Select("select * from user") List<User> getAllUser(); @Select("select * from user where id=#{id}") User getUserById(int id); @Delete("delete from user where id=#{id}") void deleteUserById(int id); @Update("update user set name=#{newName} where id=#{id}") void updateUser(@Param("id") int id, @Param("newName") String newName); @Insert("insert into user values(NULL, #{username}, #{password})") void insertUser(@Param("username")String username, @Param("password")String password); }

    解决多参数问题

    使用POJO封装。使用Map使用@Param注解 : 适用基本数据类型 + String @Insert("insert into user values(NULL, #{username}, #{password})") void insertUser(@Param("username")String username, @Param("password")String password);

    #{} 和 ${} 的区别

            #{}是带有预编译, 很大程度上能防止SQL注入的问题,而使用${}是不安全的。

    复杂语句查询:

    表和POJO

    Student public class Student { private int id; private String name; // 学生需要关联一个的老师 private Teacher teacher; // getter/setter/toString省略 } Teacher public class Teacher { private int id; private String name; // 多个学生 List<Student> studentList; // getter/setter/toString省略 }

    多对一:association

            表示多对一当中的那个多的POJO当中的表示一的那个对象,比如Student类中设置了一个Teacher成员。

            查询所有学生的信息以及对应的老师的信息:

    类似子查询方式 : <mapper namespace="dao.StudentMapper"> <!-- 配置多对一关系映射 --> <resultMap id="StudentTeacher" type="pojo.Student"> <!-- property : POJO的属性。 column : 外键字段。 javaType : POJO的属性的类型。 --> <association property="teacher" column="tid" javaType="pojo.Teacher" select="getTeacher"/> </resultMap> <!-- 查询所有学生 --> <select id="getAllStudent" resultMap="StudentTeacher" resultType="pojo.Student"> select * from student </select> <select id="getTeacher" resultType="pojo.Teacher"> select * from teacher where id=#{id} </select> </mapper> 联接查询方式 : <resultMap id="StudentTeacherInnerJoin" type="pojo.Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <!-- property : POJO的属性。 javaType : POJO的属性的类型。 --> <association property="teacher" javaType="pojo.Teacher"> <result property="name" column="tname"/> </association> </resultMap> <select id="getAllStudentUserInnerJoin" resultMap="StudentTeacherInnerJoin" resultType="pojo.Student"> select s.id sid, s.name sname, t.name tname from student as s, teacher as t where s.tid=t.id; </select>

    一对多:collection

            表示多对一当中的那个一的POJO当中的表示多那个对象,比如Teacher类中设置了一个Student的集合成员。

            需求:查询指定老师和其所有的学生。

    类似查询方式: <mapper namespace="dao.TeacherMapper"> <select id="getTeacherById" resultType="pojo.Teacher" resultMap="TeacherStudent"> select * from teacher where id=#{id} </select> <resultMap id="TeacherStudent" type="pojo.Teacher"> <!-- property : POJO的属性 javaType : POJO属性的类型 ofType : 集合的泛型 select : 使用的子查询。 --> <collection property="students" javaType="ArrayList" ofType="pojo.Student" select="getStudentByTeacherId" column="id"/> </resultMap> <select id="getStudentByTeacherId" resultType="pojo.Student"> select * from student where tid=#{tid} </select> </mapper> 联接查询方式: <mapper namespace="dao.TeacherMapper"> <resultMap id="TeacherStudent" type="pojo.Teacher"> <result property="name" column="tname"/> <!-- property : POJO的属性。 ofType : 集合的泛型的类型。 --> <collection property="students" ofType="pojo.Student"> <result property="name" column="sname"/> </collection> </resultMap> <select id="getTeacherById" parameterType="int" resultMap="TeacherStudent" resultType="pojo.Teacher"> select t.name tname, s.name sname from teacher as t, student as s where t.id=#{id} and t.id=s.tid </select> </mapper>

    动态SQL

             动态SQL就是方法传入的参数不同条件生成不同的SQL语句。其目的是为了简化SQL语句拼接的问题

            这里直接看文档就行了

    缓存

    简介

    一次查询的结果,暂时存放到一个地方,当还要查询的时候,直接去缓存里面查询。(经常使用且不经常改变的数据)。

    MyBatis缓存

         MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存的。

    默认情况下的,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)二级缓存需要手动开启,namespace(一个Mapper)级别的缓存。还提供自定义方式,实现二级缓存。

    一级缓存

        在SqlSession 和 其close之间使用。

    缓存失效的情况:

    映射文件中select语句将被缓存,但查询条件不一致则不会被缓存。映射语句中的insert, update, delete 会刷新缓存, 即使更新的东西不是缓存里的内容。缓存会使用规定策略删除一定的缓存,比如LRU,最近最少使用。缓存会定时进行刷新。手动清理缓存。 sqlSession.clearCache();

    二级缓存:

    工作机制

    所有的数据会先存放在一级混村中哦哦那个。当会话提交或者关闭的时候才会提交到二级缓存中。搜索的时候选从二级缓存当中寻找,再去一级缓存中寻找,找不到再查找。

    核心配置文件

    <settings> <setting name="cacheEnable" value="true"></setting> </settings>

    mapper.xml

        只需要在mapper.xml中添加如下一个标签:

    <cache eviction = "FIFO" // 缓存策略 flushInterval="60000" // 刷新缓存的时间 size="512" // 缓存的大小 readOnly="true" // 只读 />
    Processed: 0.009, SQL: 12