MyBatis快速入门

929 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

2.4 MyBatis

  • Mybatis 是一款优秀的持久层框架,用于简化 JDBC开发,它支持定制化 SQL、存储过程以及高级映射。
    • 持久层就是负责将数据保存到数据库的那一层代码。
    • JavaEE三层架构:表现层、业务层、持久层。
    • 表现层:页面展示的。
    • 业务层:使用来做逻辑处理的。
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。2013年11月迁移到Github
  • 英文网
  • 中文网
  • mybatis-spring

2.4.1 MyBatis快速入门

pom.xml内容

 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
 
     <!--当前项目的坐标-->
     <groupId>com.itlaity</groupId>
     <artifactId>maven-demo</artifactId>
     <version>1.0-SNAPSHOT</version>
 
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
     </properties>
 
     <!--导入mysql 驱动 jar包-->
     <dependencies>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.48</version>
         </dependency>
 
         <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
             <version>1.1.12</version>
         </dependency>
         <!--单元测试的坐标-->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.13</version>
             <scope>test</scope>
         </dependency>
         <!-- mybatis 依赖 -->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.5</version>
         </dependency>
 
         <!-- 添加日志支持 -->
         <!-- log4j日志系统 -->
         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
         </dependency>
         <!-- simple logg facade for java(slf4-api.jar)日志接口 和 log4j具体日志系统之间的适配器 -->
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>1.7.20</version>
         </dependency>
         <!-- 添加logback-classic依赖 -->
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <version>1.2.3</version>
         </dependency>
 
         <!-- 安装logback-core 依赖-->
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-core</artifactId>
             <version>1.2.3</version>
         </dependency>
     </dependencies>
 </project>

放到src/main/resources/ 的日志配置文件logback.xml

 <?xml version="1.0" encoding="UTF-8"?>
 <!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
 <!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
 <!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
 <!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
 <!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
 <!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
 <configuration scan="true" scanPeriod="60 seconds"
     debug="false">
     <!-- 动态日志级别 -->
     <jmxConfigurator />
     <!-- 定义日志文件 输出位置 -->
     <property name="log_dir" value="../logs" />
     <!-- <property name="log_dir" value="/home/data/logs/src" /> -->
     <!-- 日志最大的历史 30天 -->
     <property name="maxHistory" value="30" />
     <!-- ConsoleAppender 控制台输出日志 -->
     <appender name="console"    class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
             <pattern>
                 <!-- 设置日志输出格式 -->
                 [%d{yyyy-MM-dd HH:mm:ss.SSS}][%logger:%line]%-5level -- %msg%n
             </pattern>
         </encoder>
     </appender>
 
     <logger name="com.itlaity" level="DEBUG" additivity="false">
         <appender-ref ref="console"/>
     </logger>
 
     <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
     <appender name="file"   class="ch.qos.logback.core.rolling.RollingFileAppender">
         <!-- 过滤器,只记录WARN级别的日志 -->
         <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
             <level>ERROR,INFO,WARN,DEBUG</level>
         </filter>
         <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
         <rollingPolicy  class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!--日志输出位置 可相对、和绝对路径 -->
             <fileNamePattern>
                 ${log_dir}/%d{yyyy-MM-dd}/logback.log
             </fileNamePattern>
             <maxHistory>${maxHistory}</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>
                 <!-- 设置日志输出格式 -->
                 [%d{yyyy-MM-dd HH:mm:ss.SSS}][%logger:%line]%-5level -- %msg%n
             </pattern>
         </encoder>
     </appender>
     <root>
         <!-- 打印TRACE级别日志及以上级别日志 -->
         <level value="DEBUG" />
         <!-- 控制台输出 -->
         <appender-ref ref="console" />
         <!-- 文件输出 -->
         <appender-ref ref="file" />
     </root>
 </configuration>

彩色日志bogback.xml(了解)

 <?xml version="1.0" encoding="UTF-8"?>
 <configuration scan="true" scanPeriod="60 seconds" debug="false">
     <property name="APP_NAME" value="MY_APP_NAME" />
     <property name="LOG_DIR" value="logs" />
     <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}  %-5level [%thread] %logger{15} - %msg%n" />
     <!-- 彩色日志格式 -->
     <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %boldYellow([%thread])  %cyan(%logger{15}) %msg%n"/>
  
     <contextName>${APP_NAME}</contextName>
  
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
             <pattern>${CONSOLE_LOG_PATTERN}</pattern>
         </encoder>
     </appender>
  
     <appender name="FILE" class="ch.qos.logback.core.FileAppender">
         <file>${LOG_DIR}/logFile.log</file>
         <append>true</append>
         <encoder>
             <pattern>${FILE_LOG_PATTERN}</pattern>
         </encoder>
     </appender>
  
     <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <fileNamePattern>${LOG_DIR}/dayLogFile.%d{yyyy-MM-dd}.log</fileNamePattern>
             <maxHistory>30</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${FILE_LOG_PATTERN}</pattern>
         </encoder>
     </appender>
  
     <!-- 使用root的appender-ref -->
     <logger name="com.example.Logger1" level="DEBUG" additivity="true">
     </logger>
  
     <!-- 不使用root的appender-ref -->
     <logger name="com.example.Logger2" level="DEBUG" additivity="false">
     </logger>
  
     <logger name="com.example.Logger3" level="DEBUG" additivity="false">
         <appender-ref ref="STDOUT"/>
     </logger>
  
     <root level="DEBUG">
         <appender-ref ref="STDOUT" />
         <appender-ref ref="FILE" />
         <appender-ref ref="RollingFile" />
     </root>
 </configuration>

放到src/main/resources/ 的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:///java?useSSL=false"/>
                 <property name="username" value="root"/>
                 <property name="password" value="wang9264"/>
             </dataSource>
         </environment>
     </environments>
     <mappers>
         <!--加载sql映射文件  自建-->
         <mapper resource="UserMapper.xml"/>
     </mappers>
 </configuration>

放到src/main/resources/ 的映射的 SQL 语句文件

注意文件名称一定是有标识性的 例如:对用户表进行操作 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">
 
 <!--
 namespace:名称空间
 resultType:对应你建立的包名
 id:唯一标识不能重复
 -->
 <mapper namespace="test">
     <select id="selectAll" resultType="com.itlaity.pojo.User">
         select * from mybatis_user;
     </select>
 </mapper>

开始写代码src\main\java\com\itlaity\pojo\User.java

 package com.itlaity.pojo;
 
 /**
  * @author : Laity
  * @Project: JavaLaity
  * @Package com.itlaity
  * @date Date : 2021年12月12日 1:37
  * @Description: 实体类
  */
 
 // 按住atl+鼠标左键 整列编辑
 public class User {
     private Integer id;
     private String username;
     private String password;
     private char gender;
     private String addr;
 
     // 添加get和set方法
 
     /**
      * 在java中,为了保证数据的安全性,
      * 我们会把数据定义为private等(私有、封装),
      * 如果想要调用就会用到set()方法与get方法或者构造函数方法。
      * 这里说的是第一种方法,set()与get()
      */
     public Integer getId() {
         return id;
     }
 
     public void setId(Integer id) {
         this.id = id;
     }
 
     public String getUsername() {
         return username;
     }
 
     public void setUsername(String username) {
         this.username = username;
     }
 
     public String getPassword() {
         return password;
     }
 
     public void setPassword(String password) {
         this.password = password;
     }
 
     public char getGender() {
         return gender;
     }
 
     public void setGender(char gender) {
         this.gender = gender;
     }
 
     public String getAddr() {
         return addr;
     }
 
     public void setAddr(String addr) {
         this.addr = addr;
     }
 
     @Override
     public String toString() {
         return "User{" +
                 "id=" + id +
                 ", username='" + username + '\'' +
                 ", password='" + password + '\'' +
                 ", gender=" + gender +
                 ", addr='" + addr + '\'' +
                 '}';
     }
 }

测试类src\main\java\com\itlaity\MyBatisDemo.java

 package com.itlaity;
 
 import com.itlaity.pojo.User;
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 
 import java.io.InputStream;
 import java.util.List;
 
 /**
  * @author : Laity
  * @Project: JavaLaity
  * @Package com.itlaity
  * @date Date : 2021年12月12日 1:55
  * @Description: 测试类
  */
 public class MyBatisDemo {
     public static void main(String[] args) throws Exception {
         // 1. 加载mybatis的核心配置文件,获取 SqlSessionFactory类的对象
         String resource = "mybatis-config.xml";
         // 返回字节输入流
         InputStream inputStream = Resources.getResourceAsStream(resource);
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 
         // 2. 获取 SqlSession对象 执行sql语句
         SqlSession sqlSession = sqlSessionFactory.openSession();
 
         // 3. 执行sql
         List<User> users = sqlSession.selectList("test.selectAll");
 
         System.out.println(users);
 
         // 释放资源
         sqlSession.close();
     }
 }

如果你认为麻烦

同学我送你一句话: 今朝有酒,今朝醉。明日愁来,明日愁。

2.4.2 Mapper代理开发

  • 解决原生方法中的硬编码
  • 简化后期执行SQL

设置SQL映射文件的namespace

  • 定义一个与sql映射文件同名的mapper接口,并且将Mapper接口和sql映射文件放置在同一目录下(创建目录用 / 来创建)

  • 属性为Mapper接口权限定名

  • 在mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致

    •  List<User> selectAll();
      
  • 编码

    • 通过SqlSession的getMapper方法获取 Mapper接口的代理对象
    • 调用对应方法完成sql执行
 <?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">
 
 <!--
 namespace:名称空间
 resultType:对应你建立的包名
 id:唯一标识不能重复
 -->
 <!--设置SQL映射文件的namespace属性为Mapper接口权限定名-->
 <mapper namespace="com.itlaity.mapper.UserMapper">
     <select id="selectAll" resultType="com.itlaity.pojo.User">
         select *
         from mybatis_user;
     </select>
 </mapper>

2.4.3 特殊字符处理

 // 在编写sql语句中
 参数占位符
     1.#{} :执行sql时,会将#{}占位符替换成 ?,将来自动设置参数值
     2.${} :拼sql,会存在sql注入问题。
 
 parameterType:
     用于设置参数类型,该参数可以省略。
     
 < 是写不了的 怎么解决呢
     1.转义字符
     2.CDATA区

2.4.4 注解完成增删改查

  • 增(insert)

    • 注意默认开启事务:需要手动提交事务 sqlSession.commit();
    • 或者在获取 SqlSession时 添加参数 true
    • 主键返回:在数据添加成功后,需要获取插入数据库的主键的值
    • 只需在sql语句中参加两个属性: useGeneratedKeys 和 KeyProperty
    • 返回结果 void
  • 修改(updata)

    • 修改全部字段 上面的JDBC就已经学过
    • 修改动态字段 书写动态SQL语句
      • where id = #{id}
  • 删除(delete)

    • 删除一个

      • delete from 表 where id = #{id}
    • 删除多个

      •  void deleteByids(@Param("ids") int[] ids)  // @Param("ids")注解改变map集合的默认key的名称
        
      • delete from 表 where id in <foreach collection="ids" item="id" separator="," open="("  close=")">  #{id} </foreach>
        
  • 结论 :大多数参数都封装为Map集合,可以使用@Param 注解,替换Map集合中默认的arg键名 param键名。

2.4.5 动态SQL

 // 在编写sql语句中(多条件查询)
 动态sql(搜索添加一个需要三个参数,但用户只输入1个参数)
     1.我们需加条件判断即可
     2.<if test="参数 != null and 参数!= '' "> 执行要求参数 </if>
     3.问题: 第一个条件不需要逻辑运算符
         1. 解决方案 :恒等式 1=1/ <where> 替换 where 关键字
 // 单条件查询
 <choose> <!--相当于 switch--> 
     <when> <!--相当于 case-->
     </when>
     <otherwise><!--default-->
         1 = 1    
     </otherwise>
 </choose>

2.4.6 注解开发

  • 查询:@Select
  • 添加:@Insert
  • 修改:@Updata
  • 删除:@Delete
  • 提示:注解完成简单功能,配置文件完成复杂功能。
 // 在maaper接口中写
 @select("sql语句")
 User selectById();
 // UserMapper.xml中就不需要写了