一、Mybatis的引入

  1. MyBatis是一款优秀的持久层框架;
  2. 它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。
  3. MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO (Plain OldJava Objects,普通老式Java对象)为数据库中的记录。
  4. MyBatis本是apache的一个开源项目ibatis, 2010年这个项目i山apache迁移到了googlecode,并且改名为MyBatis ORM对象关系映射

  5. Mybatis就是帮助程序猿将数据存入数据库中,和从数据库中取数据、

  6. 传统的jdbc操作,有很多重复代码块.比如:数据取出时的封装,数据库的建立连接等,通过框架可以减少重复代码,提高开发效率.
  7. MyBatis是一 个半自动化的ORM框架(ObjectRelationshipMapping)

    —>对象关系映射(半自动化需要自己写sql语句)

  8. MyBatis官网:https://mybatis.org/mybatis-3/zh/index.html

优势:MyBatis的真正强大在于它的映射语句,这是它的优势所在。由于它的异常强大,映射器的XML文件就显得相对简单。如果拿它跟具有相同功能的JDBC代码进行对比,会立即发现省掉了将近95%的代码。MyBatis为聚焦于SQL而构建,以尽可能地为你减少麻烦

二、MyBatis使用

2.1 基于XML配置

2.1.1 配置Meavn文件,导入所有可能用到的资源

image.png

2.1.2 xml文件配置流程

image.png
image.png

数据库连接池:池中存储数据库连接对象,可以避免每次使用数据库连接对象都要重新创建,导致内存浪费。
单例的,只存储一份。

在java文件夹下配置的的包结构一定要在资源包下一样的设置。
image.png

2.1.3在xml文件下编写sql语句。

image.png

2.1.4 在test文件夹下创建测试类,注意写法
  1. public class MyBatis {
  2. @Test
  3. public void test01(){
  4. try {
  5. //根据流来读取mybatis核心配置文件,然后再读取相关数据
  6. InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
  7. //创建sqlSessionFactory对象
  8. SqlSessionFactory sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder().build(resourceAsStream);
  9. //sqlSession从工厂中取出来。
  10. SqlSession sqlSession = sqlSessionFactoryBuilder.openSession();
  11. //maybatis会在底层通过动态代理的方式为持久层创建对应的实现类。
  12. UserDao userdao = sqlSession.getMapper(UserDao.class);
  13. List<User> userlist = userdao.getuserlist();
  14. for (User user : userlist) {
  15. System.out.println(user);
  16. }
  17. //关闭资源
  18. sqlSession.close();
  19. resourceAsStream.close();
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

2.2 底层原理

mybatis不需要实现类只需要接口,直接只用接口就行,mybatis底层通过例如。

  1. mybatis注解方式是怎样通过没有实现类的dao接口进行数据库操作 解答: 1)原理上:JDK动态动态代理的原理是根据 InvocationHandler 中的invoke()方法,由jdk为你的接口手动生成了一个实现了对应接口的类,因此,你的接口可以调用,这是理解mybatis接口没有实现类能被调用的关键。

2)功能上:可以看出mybatis中的接口就是XML文件的描述,一方面这样做的目的是和spring集成,将接口交给spring管理;另一方面是为了更加方便的管理XML文件(使用接口的package+interface作为namespace,method作为ID。

  1. public class MyBatisTest {
  2. SqlSession sqlSession = null;
  3. InputStream resourceAsStream = null;
  4. /**
  5. * @Before 在所有测试单元执行之前执行
  6. */
  7. @Before
  8. public void mybatisBefore(){
  9. try {
  10. //根据流来读取mybatis的核心配置文件,然后读取相关数据
  11. resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
  12. } catch (IOException ioException) {
  13. ioException.printStackTrace();
  14. }
  15. //创建sqlSessionFactory对象
  16. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
  17. //将sqlSession从工厂中取出来
  18. sqlSession = sqlSessionFactory.openSession();
  19. }
  20. /**
  21. * @After在所有测试单元执行之后执行
  22. */
  23. @After
  24. public void mybatisAfter(){
  25. //关闭资源
  26. if (sqlSession != null){
  27. sqlSession.close();
  28. }
  29. if (resourceAsStream != null){
  30. try {
  31. resourceAsStream.close();
  32. } catch (IOException ioException) {
  33. ioException.printStackTrace();
  34. }
  35. }
  36. }
  37. @Test
  38. public void test01(){
  39. //mybatis会在底层通过动态代理的方式来为持久层接口创建对应的实现类
  40. UserDao userDao = sqlSession.getMapper(UserDao.class);
  41. //查询用户信息
  42. List<User> userList = userDao.getUserList();
  43. //遍历集合
  44. for (User user : userList) {
  45. System.out.println(user);
  46. }
  47. }
  48. @Test
  49. public void test02(){
  50. //创建持久层的实例
  51. UserDao userDao = new UserDaoImpl(sqlSession);
  52. //查询用户信息
  53. List<User> userList = userDao.getUserList();
  54. //遍历集合
  55. for (User user : userList) {
  56. System.out.println(user);
  57. }
  58. }
  59. @Test
  60. public void test03(){
  61. //获取代理对象
  62. UserDao userDao = (UserDao)getProxy();
  63. List<User> userList = userDao.getUserList();
  64. for (User user : userList) {
  65. System.out.println(user);
  66. }
  67. }
  68. /**
  69. * 模拟mybatis底层通过动态代理来创建持久层的实现类
  70. * @return
  71. */
  72. public Object getProxy(){
  73. return Proxy.newProxyInstance(UserDao.class.getClassLoader(), new Class[]{UserDao.class}, new InvocationHandler() {
  74. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  75. Object invoke = method.invoke(new UserDao() {
  76. public List<User> getUserList() {
  77. List<User> users = sqlSession.selectList("com.eagleslab.dao.UserDao.getUserList");
  78. return users;
  79. }
  80. });
  81. return invoke;
  82. }
  83. });
  84. }
  85. }

2.3 使用流程

  1. 在java文件夹下:创建实体类(也是接受类);
  2. 在java文件夹下:写一个接口,包含我们要使用到的方法;
  3. 在资源文件夹下:创建映射的xml文件:命名空间换为接口的全类名;

    1. id为方法的全局变量、以及返回类型使用对应的实体类的全类名
    1. <!--建立起实体属性和表字段的对应关系-->
    2. <resultType id="getstudentlist" type="com.eagleslab.pojo.Student">
  1. 在资源文件夹下:核心配置文件对上面的xml文件进行声明


  1. 在test文件夹下:

首先先建立使用的框架:主要就是使用
@Before

  • 根据流来读取mybatis的核心配置文件,然后读取相关数据
  • 创建sqlSessionFactory对象
  • 将sqlSession从工厂中取出来

@After

  • 提交事务
  • 关闭资源 ```java public class MyBatisTest02 { SqlSession sqlSession = null;

    InputStream resourceAsStream = null;

    /**

    • @Before 在所有测试单元执行之前执行 */ @Before public void mybatisBefore(){
  1. try {
  2. //根据流来读取mybatis的核心配置文件,然后读取相关数据
  3. resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
  4. } catch (IOException ioException) {
  5. ioException.printStackTrace();
  6. }
  7. //创建sqlSessionFactory对象
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
  9. //将sqlSession从工厂中取出来
  10. sqlSession = sqlSessionFactory.openSession();
  11. }
  12. /**
  13. * @After在所有测试单元执行之后执行
  14. */
  15. @After
  16. public void mybatisAfter(){
  17. //提交事务
  18. sqlSession.commit();
  19. //关闭资源
  20. if (sqlSession != null){
  21. sqlSession.close();
  22. }
  23. if (resourceAsStream != null){
  24. try {
  25. resourceAsStream.close();
  26. } catch (IOException ioException) {
  27. ioException.printStackTrace();
  28. }
  29. }
  30. }
  1. ```java
  2. @Test
  3. public void test01(){
  4. //获取代理对象
  5. StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  6. //查询所有的学生数据
  7. List<Student> studentList = studentDao.getStudentList();
  8. //遍历集合
  9. for (Student student : studentList) {
  10. System.out.println(student);
  11. }
  12. }
  1. 补充

当我们使用到的实体类字段与数据库中的表的字段名字不符合时,可以使用到如下标签进行解决

  1. <!--建立起实体属性和表字段的对应关系-->
  2. <resultMap id="studentVo" type="com.eagleslab.pojo.Student">
  3. <!--注意后面使用方法的全类名可以使用studentVo来替代-->
  4. <!--匹配主键字段-->
  5. <id property="sid" column="id"></id>
  6. <!--匹配非主键字段-->
  7. <result property="stuName" column="name"></result>
  8. <result property="age" column="age"></result>
  9. <result property="sex" column="sex"></result>
  10. <result property="birthday" column="birthday"></result>
  11. <result property="address" column="address"></result>
  12. </resultMap>

其他操作:

{} OGM表达式 : 可以防止sql注入,但是不能进行字符串拼接
${} el表达式

  1. <!--添加学生-->
  2. <!--
  3. #{} OGM表达式 : 可以防止sql注入
  4. ${} el表达式
  5. -->
  6. <insert id="addStudent" parameterType="com.eagleslab.pojo.Student">
  7. insert into tb_student(name,age,sex,birthday,address) values (#{stuName},#{age},#{sex},#{birthday},#{address})
  8. </insert>
  9. <!--根据id来修改学生数据-->
  10. <update id="updateStudentById" parameterType="com.eagleslab.pojo.Student">
  11. update tb_student set name = #{stuName},age = #{age},sex = #{sex},birthday = #{birthday},address = #{address} where id = #{sid}
  12. </update>
  13. <!--根据id来删除学生数据-->
  14. <delete id="deleteStudentById" parameterType="int">
  15. delete from tb_student where id = #{sid}
  16. </delete>
  17. <!--根据学生姓名来模糊查询-->
  18. <select id="findStudentLikeByName" parameterType="java.lang.String" resultMap="studentVo">
  19. select * from tb_student where name like #{ewfeferefew}
  20. </select>
  21. <!--求学生的总个数-->
  22. <select id="getStudentCount" resultType="int">
  23. select count(*) from tb_student
  24. </select>

三、动态sql

3.1 定义:

动态SQL指的是根据不同的查询条件,生成

3.2 分类:

  1. if
  2. choose (when, otherwise)
    • trim (where, set)
  3. foreach

3.3 :动态sql的使用方法

使用动态sql需要使用到对应的动态标签

  1. <!--根据指定的条件来查询对应的学生数据-->
  2. <select id="getStudentList" resultMap="studentVo" parameterType="hashmap">
  3. select * from tb_student
  4. <where>
  5. <if test="name != null">
  6. and name = #{name}
  7. </if>
  8. <!--如果符合条件就对查询语句进行拼接-->
  9. <if test="sex != null">
  10. and sex = #{sex}
  11. </if>
  12. <if test="id != null">
  13. and id = #{id}
  14. </if>
  15. </where>
  16. </select>
  1. @Test
  2. public void test01(){
  3. //创建代理对象
  4. StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
  5. HashMap hashMap = new HashMap();
  6. hashMap.put("sex","男");
  7. hashMap.put("id","5");
  8. List<Student> studentList = studentMapper.getStudentList(hashMap);
  9. for (Student student : studentList) {
  10. System.out.println(student);
  11. }

四、mybatis其他

4.1延迟加载和立即加载

  1. 什么是延迟加载?

真正在使用数据的时候才发起查询,不用的时候不查询,按需加载(懒加载)

  1. 什么是立即加载?

不管用不用,一调用方法,马上发起查询:

  • 针对一对多和多对多:通常情况下使用延迟加载
  • 针对多对和一对:通常情况下使用立即加载

4.2 n对n

4.2.1 一对一、一对多、客对一、多对多
  1. 一对一:账单对用户一个账中只能对应一个用户
  2. 一对多:用户对账单一个用户可以对应多个账单
  3. 多对一:多个学生可以对应一个班级
  4. 多对多:用户和角色:一个用户可以对应多个角色,一个角色也可以对应多个用户。多对多我们一般会指定中间表:用来建立两张表之间的联系

例如:张三是一个用户:在家庭中,张三则一个父亲(角色),在企业中,足一个项目经理(角色)
多对多我们一般会指定中间表:用来建立两张表之间的联系

2,在mybatis中:

4.2.2 配置一对一

首先创建账户与用户两个类,账户类中聚合了用户类。
接下来在xml配置文件中进行如下操作:

注意:配置方式

聚合一个用户的字段的配置内容
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.eagleslab.mapper.AccountMapper">
  6. <!--建立起实体属性和表字段的对应关系-->
  7. <resultMap id="accountVo" type="com.eagleslab.pojo.Account">
  8. <!--匹配主键字段-->
  9. <id property="tid" column="tid"></id>
  10. <!--匹配非主键字段-->
  11. <result property="money" column="money"></result>
  12. <result property="uid" column="uid"></result>
  13. <!--配置一对一的关系-->
  14. <association property="user" javaType="com.eagleslab.pojo.User">
  15. <!--配置用户的字段-->
  16. <id column="id" property="uid"></id>
  17. <result column="username" property="username"></result>
  18. <result column="password" property="password"></result>
  19. </association>
  20. </resultMap>
  21. <!--根据指定的条件来查询对应的学生数据-->
  22. <select id="findAccountByAll" resultMap="accountVo">
  23. select * from ts_account a inner join user u on u.id = a.uid
  24. </select>
  25. </mapper>

配置完成后,注意将改配置文件在核心配置文件中进行注册。

4.2.3 配置一对多

首先创建账户与用户两个类,用户类中聚合了账户类。一个用户对应多个账户
接下来在xml配置文件中进行如下操作:

注意:配置方式 聚合一个账户的字段的配置内容

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.eagleslab.mapper.UserMapper">
  6. <resultMap id="userVo" type="com.eagleslab.pojo.User">
  7. <id column="id" property="uid"></id>
  8. <result column="username" property="username"></result>
  9. <result column="password" property="password"></result>
  10. <!--配置一对多-->
  11. <collection property="accounts" ofType="com.eagleslab.pojo.Account">
  12. <!--匹配主键字段-->
  13. <id property="tid" column="tid"></id>
  14. <!--匹配非主键字段-->
  15. <result property="money" column="money"></result>
  16. <result property="uid" column="uid"></result>
  17. </collection>
  18. </resultMap>
  19. <select id="getUserList" resultMap="userVo">
  20. select * from user u left join ts_account a on u.id = a.uid
  21. </select>
  22. </mapper>

4.2.4 多对多

案例:一个用户可以对应多个角色,一个角色也可以对应多个用户

  1. 首先创建:用户表、角色表、中间表(多对多一定要有中间表)
  2. 创建表对应的实体类,每个类里聚合对方类型的list,封装。
  3. 创建每个类对应的接口,接口内定义方法。
  4. 创建xml文件:
    1. <collection property="userList" ofType="com.eagleslab.pojo.User">
    2. <id column="id" property="uid"></id>
    3. <result column="username" property="username"></result>
    4. <result column="password" property="password"></result>
    5. </collection>
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.eagleslab.mapper.RoleMapper">
  6. <!--建立起实体属性和表字段的对应关系-->
  7. <resultMap id="roleVo" type="com.eagleslab.pojo.Role">
  8. <!--匹配主键字段-->
  9. <id property="rid" column="rid"></id>
  10. <!--匹配非主键字段-->
  11. <result property="roleName" column="role_name"></result>
  12. <!--配置多对多的关系-->
  13. <collection property="userList" ofType="com.eagleslab.pojo.User">
  14. <id column="id" property="uid"></id>
  15. <result column="username" property="username"></result>
  16. <result column="password" property="password"></result>
  17. </collection>
  18. </resultMap>
  19. <!--查询所有的角色数据-->
  20. <select id="getRoleList" resultMap="roleVo">
  21. select u.*,r.*
  22. from user u
  23. left join user_role ur
  24. on u.id = ur.uid
  25. left join tb_role r
  26. on r.rid = ur.rid
  27. </select>
  28. </mapper>

注意三表联查:需要两次连接,前一次作为后一次查询的子表。