SSM - Mybatis - Syntax

1. Mybatis 简介

Mybatis 官网 @ mybatis – MyBatis 3 | 简介
M
ybatis下载 GitHub @ GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java
Maven 仓库 @ Maven Repository: org.mybatis » mybatis (mvnrepository.com) , 其中POM修改如下:

    <dependency>
      <!--  mysql驱动-->
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>

    <!--  mybatis-->
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.13</version>
    </dependency>

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

 

 2. Mybatis 配置

涉及到的新文件:需要配置: POM.xml文件,resources/  mybatis-config.xml文件(定义MySQL数据库)/  UserMapper.xml文件(具体定义数据库访问接口规范)
如果遇到src/main/java/com/crevew/dao/*.xml 不打包的问题,有几种解决方案:

1. 把xml文件移到 resources目录下面,系统默认打包该文件夹下所有文件
2. 在POM.xml文件中增加以下配置,显示让maven打包;增加后,务必reload project,否则POM的修改不生效。(如果还不生效,就重启IDEA)
3. 可以在 target/classes/com/crevew/dao/ 下面核实该文件是否存在。

  <build>
  <!--配置打包时不过滤非java文件开始  -->
  <!--说明,在进行模块化开发打jar包时,maven会将非java文件过滤掉,
  xml,properties配置文件等,但是这些文件又是必需的,
  使用此配置可以在打包时将不会过滤这些必需的配置文件。
  -->
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
  </resources>
  </build>

 Mybatis Idea 编辑

Mybatis XML Idea编辑自动提示方法 (强烈推荐):@ (14条消息) IDEA Mybatis xml中配置sql代码自动提示【必看】_idea中xml如何设置自动提示_mingyuexinc的博客-CSDN博客 
Mybatis plugin @ IDEA 添加 mybatis mapper的xml文件的自动提示功能 - 简书 (jianshu.com)

3. Mybatis 语法

Mybatis查询就直接查询;增删改需要提交事务。

Mybatis Mapper.xml 参数有三种类型:
1. Object,直接在sql取对象的属性即可
2. Map传递参数,直接在sql中取出属性,用于输出多个参数  (多个参数输入 用Map或者注解)
3. 基本类型(基本类型也可以不写)

模糊查询,可以在xml sql 当中拼接(不安全),也可以在代码执行的时候传递%%

select * from mybatis.user where name like #{value}
或者
List<User> userList = mapper.getUserLike("%李%");

#{} 预编译, ${} 无预编译

 4. 配置解析

4.1 Mybatis 默认设置

默认的事务管理器是JDBC, 默认的连接池POOLED

4.2 Properties/typeAliases/Settings/Mappers

Properties: 可以通过properties属性来引用配置文件,如果配置db.properties之后,出现连接错误,原因是: @ 解决Mybatis报错:### Error querying database. Cause: java.sql.SQLException: No suitable driver found for_zhaiC_的博客-CSDN博客

typeAliases:

  • 为Java类型设置一个短的名字(DIY),减少冗余;
  • 也可以指定包名,Mybatis会自动搜索Java Bean,首字母小写;
  • 在实体类较少时,使用前者;实体类较多的时候,使用后者; 但是后者不可以DIY,如果非要改,就在POJO上面增加注解实现@Alias()

Settings: logImpl, cacheEnabled, lazyLoadingEnabled 等。 (Plugin: mybatis-generator-core, mybatis-plus, 通用mapper)

Mappers 映射器: 通过 resource,class,file(不用),package,四种方式加载mapper

4.3 作用域和生命周期

SqlSessionFactoryBuilder: 一旦创建SqlSessionFactory,就不再需要了
SqlSessionFactory: 可以想象为数据库连接池,运行期一直存在,应用作用域;单例模式,或者静态单例模式
SqlSession: 连接到连接池的一个请求,用完需要关闭

5. 映射文件

5.1 ResultMap 

解决属性名和字段名不一致的问题。问题是:数据库的字段名称,和pojo属性不一致。

方法一:别名

    <select id="getUserById" parameterType="int" resultType="UserAlias">
        select id,name,pwd as password from mybatis.user where id = #{id}
    </select>

方法二:ResultMap 结果集映射

6. 日志

logImpl: 重点是LOG4J, STDOUT_LOGGING

LOG4J 配置文件设置 @ (15条消息) LOG4J的配置文件_log4j配置文件_小逗比iswho的博客-CSDN博客 

7. 分页

1. 使用SQL语句的limit实现分页,比如:select * from mybatis.user limit 1,2
2. 使用RowBounds分页,比如 

        //通过RowBounds实现
        RowBounds rowBounds = new RowBounds(1, 2);
        //通过Java代码层面实现分页
        List<User> userList = sqlSession.selectList("com.crevew.dao.UserMapper.getUserByRowBounds",null, rowBounds);

3. 分页插件: MyBatis PageHelper

8. 注解开发

关于接口的理解:

  • 接口从更深层次的理解,应是定义(规范、约束)与实现(名实分离的原则)的分离。
  • 接口的本身反映了系统设计人员对系统的抽象理解。
  • 接口应有两类:第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)。
  • 一个个体可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

  • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法。
  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。
  • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题。更多的体现就是对系统整体架构。

注解和XML配置,可以同时使用。 注解的使用方法就是:在接口上实现。

  • 本质:反射机制实现。
  • 底层:动态代理。

9. Lombok

Lombok安装方式有三部,IDEA安装,POM引用,接口使用。详见 @ (15条消息) idea中怎么使用lombok依赖_idea依赖树只有lombok_南商的博客-CSDN博客

10. 多对一处理

实验环境搭建: @ (15条消息) Mybatis一对多,多对一_mybatis一对多 多对一_羊村跳水冠军个人学习笔记的博客-CSDN博客

 方法一:按照查询嵌套处理,相当于子查询

<!-- 思路:
1. 查询所有的学生信息;
2. 根据查询出来的学生id,寻找对应的老师,子查询
3. -->
  <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>
    
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--复杂的属性,我们需要单独处理. 对象: association; 集合: collection -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    
    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id=#{id}
    </select>

方法二:按照结果嵌套处理,相当于连表查询

    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid, s.name sname, t.name tname, t.id tid
        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="name" column="tname"/>
            <result property="id" column="tid"/>
        </association>
    </resultMap>

11. 一对多处理

方法一:按照查询嵌套处理

    <!--按照查询进行-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id=#{tid}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="Student">
        select * from mybatis.student where tid=#{id}
    </select>

方法二:按照结果嵌套处理

    <!--按照结果查询-->
    <select id="getTeacher" resultMap="TeacherStudent">
        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>
    
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!-- 对象association; 集合collection
        集合中的泛型信息,我们使用ofType获得-->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

小结:

  • 关联--- association
  • 集合---collection
    •   javaType 用来指定实体类中属性的类型
    •   ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!

12. 动态SQL

动态SQL就是根据不同的条件生成不同的SQL语句. 所谓的动态SQL,本质还是SQL语句, 只是在SQL层面,去执行一个逻辑代码
主要关键词: if (test), choose  (when, otherwise),  trim (where, set), foreach
动态SQL就是拼接SQL,一般建议在MySQL中写出完整的SQL,再对应修改相应的动态语句。

 

SQL片段,相当于SQL函数 (最好基于单标,最好不要存在where标签等)

    <sql id="if-title-author">
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </sql>

    <insert id="updateBlog" parameterType="Blog">
        update mybatis.blog
        <set>
            <include refid="if-title-author"/>
        </set>
    </insert>

 13. 缓存

一级缓存,默认开启,无法关闭,只在一次SqlSession中有效。

二级缓存,手动开启

  • 二级缓存,也叫全局缓存;一级缓存作用域太低了,所以诞生了二级缓存。
  • 基于namepsace级别的缓存,一个名称空间,对应一个二级缓存;
  • 只要开启二级缓存,需要序列化
  • 工作机制是:
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没有了,但是我们想要的是,即使会话关闭,一级缓存的数据被保存到二级缓存中。
    • 新的会话查询信息,就可以从二级缓存中获取内容。
    • 不同的mapper查出的数据会被放在自己对应的缓存中。

第三方缓存:ehcache 是一个Java缓存机制,早期在Hibernate里使用后。现在,一般都是使用Redis作为缓存。

 

附录

 Teacher/Student表

CREATE TABLE `teacher` (
  `id` INT NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4;

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4;

INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

 博客表

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客ID',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`auther` VARCHAR(30) NOT NULL COMMENT '博客作者',
`creat_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=UTF8MB4

 

posted @ 2023-07-11 23:10  zjfun  阅读(18)  评论(0)    收藏  举报