MyBatis01

文章目录

  • 一、传统JDBC弊端
  • 二、ORM框架MyBatis介绍
  • 三、MyBatis快速开始&配置详解
      • 一、MyBatis快速开始
      • 二、配置详解
        • 一、properties
        • 二、settings
        • 三、typeAliases(类型别名)
        • 四、typeHandlers
        • 五、mappers
  • 四、MyBatis xml 与 annotation 优缺点
  • 五、Mybatis插件(plugin)
  • 六、逆向工程
      • 一、添加配置文件
      • 二、执行命令:mvn mybatis-generator:generate
      • 三、javaClientGenerator
      • 四、测试

一、传统JDBC弊端

  1. jdbc底层没有用连接池、操作数据库需要频繁的创建和关联链接。消耗很大的资源。
  2. 写原生的jdbc代码在java中,一旦我们要修改sql的话,java需要整体编译,不利于系统维护。
  3. 使用PreparedStatement预编译的话对变量进行设置123数字,这样的序号不利于维护。
  4. 返回result结果集也需要硬编码。

二、ORM框架MyBatis介绍

    MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

三、MyBatis快速开始&配置详解

一、MyBatis快速开始

  1. 登陆官网
    MyBatis01_第1张图片
<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.4version>
dependency>
  1. 创建一个test类
    MyBatis01_第2张图片
@Slf4j
public class MyBatisTest {

    @Test
    public void test() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        try (SqlSession session = sqlSessionFactory.openSession()) {
            User user = session.selectOne("org.mybatis.example.BlogMapper.selectUser", 1);
            log.info("user:{}",user);
        }
    }

  1. 创建mybatis-config.xml
    MyBatis01_第3张图片


<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/zj_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    <mappers>
        <mapper resource="mybatis/UserMapper.xml"/>
    mappers>
configuration>
  1. test类中添加执行SQL代码
    MyBatis01_第4张图片
@Slf4j
public class MyBatisTest {

    @Test
    public void test() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        try (SqlSession session = sqlSessionFactory.openSession()) {
            User user = session.selectOne("org.mybatis.example.BlogMapper.selectUser", 1);
            log.info("user:{}",user);
        }
    }

  1. 创建Mapper.xml文件
    MyBatis01_第5张图片


<mapper namespace="org.mybatis.example.BlogMapper">
    <select id="selectUser" resultType="zj.cn.mybatis.pojo.User">
    select * from user where id = #{id}
  select>
mapper>
  1. 代码目录结构,代码在最后上传
    MyBatis01_第6张图片
package zj.cn.mybatis.pojo;

import lombok.ToString;
import org.apache.ibatis.type.Alias;

import java.io.Serializable;
import java.util.Date;

@ToString
public class User implements Serializable{

  private Integer id;
  private String name;
  private  Integer age;
  private String phone;
  private Date desc;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Integer getAge() {
    return age;
  }

  public void setAge(Integer age) {
    this.age = age;
  }

  public String getPhone() {
    return phone;
  }

  public void setPhone(String phone) {
    this.phone = phone;
  }

  public Date getDesc() {
    return desc;
  }

  public void setDesc(Date desc) {
    this.desc = desc;
  }

}

二、配置详解

    配置文件:mybatis-config.xml中

<configuration>

configuration>

官网给我们做了一一的介绍
MyBatis01_第7张图片

一、properties

  1. 创建config.properties
#需要的数据库驱动
driver=com.mysql.cj.jdbc.Driver
#数据库名路径
url=jdbc:mysql://localhost:3306/zj_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT
#用户名
username=root
#密码
password=123456
  1. 在mybatis-config.xml中添加properties属性


<configuration>
    <properties resource="config.properties">
        
    	<property name="password" value="root"/>
    properties>
    <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="mybatis/UserMapper.xml"/>
    mappers>
configuration>

二、settings

第三节课讲

三、typeAliases(类型别名)

  1. 类路径比较长,用一个别名来代替。
    比如UserMapper.xml中resultType="zj.cn.mybatis.pojo.User"太长,用一个别名类代替


<configuration>
    <properties resource="config.properties">
        
        <property name="password" value="root"/>
    properties>
    <typeAliases>
        
        <typeAlias type="zj.cn.mybatis.pojo.User" alias="abc"/>
    typeAliases>
    <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="mybatis/UserMapper.xml"/>
    mappers>
configuration>


<mapper namespace="org.mybatis.example.BlogMapper">
    <select id="selectUser" resultType="abc">
    select * from user where id = #{id}
  select>
mapper>
  1. 将整个包路径下的类都做别名处理
    首先添加
<typeAliases>

  <package name="domain.blog"/>
typeAliases>

然后在domain.blog路径下的类上添加注解标记@Alias(“abc”),表示它的别名是abc,如果不加这个注解默认的别名为类名小写:author

@Alias("abc")
public class Author {
    ...
}


<configuration>
    <properties resource="config.properties">
        
        <property name="password" value="root"/>
    properties>
    <typeAliases>
        
        
        
        <package name="zj.cn.mybatis.pojo"/>
    typeAliases>
    <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="mybatis/UserMapper.xml"/>
    mappers>
configuration>

四、typeHandlers

  1. 无论是 MyBatis 在预处理语句中设置一个参数,还是从结果集中取出一个值时,类型处理器(Type Handler)被用来将获取的值以合适的方式转换成 Java 类型。下面这个表格描述了默认的类型处理器。
    MyBatis01_第8张图片
  2. 你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。要这样做的话,简单实现 TypeHandler 接口(org.mybatis.type),然后映射新的类型处理器类到 Java 类型,还有可选的一个 JDBC 类型。例如:将数据库中的VARCHAR类型,转换成java的Date类型

新建 BatTypeHandler 类,实现 TypeHandler 接口

package zj.cn.mybatis.hander;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class BatTypeHandler implements TypeHandler<Date> {

   // 设置sql中指定索引的参数,即将javaType转化为jdbcType
   @Override
   public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      ps.setString(i, simpleDateFormat.format(parameter));
   }

   // 根据列名称从结果集获取值,并将jdbcType转换成javaType
   @Override
   public Date getResult(ResultSet rs, int columnIndex) throws SQLException {
      String columnValue = rs.getString(columnIndex);
      if (null != columnValue) {
         return new Date(Long.valueOf(columnValue));
      }
      return null;
   }

   // 根据列名称从结果集获取值,并将jdbcType转换成javaType
   @Override
   public Date getResult(ResultSet rs, String columnName) throws SQLException {
      String columnValue = rs.getString(columnName);
      if (null != columnValue) {
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         try {
            return format.parse(columnValue);
         } catch (ParseException e) {
            return  null;
         }

      }
      return null;
   }

   @Override
   public Date getResult(CallableStatement cs, int columnIndex) throws SQLException {
      String columnValue = cs.getString(columnIndex);
      if (null != columnValue) {
         return new Date(Long.valueOf(columnValue));
      }
      return null;
   }
}

mybatis-config.xml中添加配置:

<typeHandlers>
    <typeHandler handler="zj.cn.mybatis.hander.BatTypeHandler" jdbcType="VARCHAR" javaType="Date">typeHandler>
typeHandlers>

五、mappers

mapper加载方式

  1. resource = xxxxMapper.xml 路径;这种使用的是XML(MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO为数据库中的记录)

<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
mappers>
  1. 这种暂时没讲

<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
mappers>

  1. class = UserMapper(这是一个接口)路径;这种使用的是注解(MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO为数据库中的记录)
package zj.cn.mybatis.mapper;

import org.apache.ibatis.annotations.Select;
import zj.cn.mybatis.pojo.User;

public interface UserMapper {
 /*  @Results({
           @Result(property ="name",column = "username")
   })*/
   @Select("select id,username as name,age,phone,`desc` from User where id = #{id}")
   public User selectUser(Integer id);
}


<mappers>
  <mapper class="zj.cn.mybatis.mapper.UserMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
mappers>
  1. 这种暂时没讲

<mappers>
  <package name="org.mybatis.builder"/>
mappers>

四、MyBatis xml 与 annotation 优缺点

Annotaion方式:

  1. 不适合比较复杂的sql 比如关联查询
  2. 不方便管理(收集)sql

Xml方式:

  1. 增加xml文件的复杂性
  2. 对于条件判断的SQL语句(动态SQL语句),不确定最终的查询语句是什么
  3. 特殊字符转义(特殊字符特指:<, >)

五、Mybatis插件(plugin)

    MyBatis 允许你在某一点拦截已映射语句执行的调用。默认情况下,MyBatis 允许使用插件来拦截方法调用:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

    这些类中方法的详情可以通过查看每个方法的签名来发现,而且它们的源代码存在于MyBatis 的发行包中。你应该理解你所覆盖方法的行为,假设你所做的要比监视调用要多。如果你尝试修改或覆盖一个给定的方法,你可能会打破 MyBatis 的核心。这是低层次的类和方法,要谨慎使用插件。使用插件是它们提供的非常简单的力量。简单实现拦截器接口,要确定你想拦截的指定签名。
例如:在执行SQL的时候增加拦截,打印SQL的执行时间,和具体执行的SQL。
首先,新建实现 Interceptor 接口的 SqlPrintInterceptor 类

package zj.cn.mybatis.plugin;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;

@Intercepts
        ({
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
        })
public class SqlPrintInterceptor implements Interceptor{

    private static final Logger log = LoggerFactory.getLogger(SqlPrintInterceptor.class);

    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameterObject = null;
        if (invocation.getArgs().length > 1) {
            parameterObject = invocation.getArgs()[1];
        }
        long start = System.currentTimeMillis();
        Object result = invocation.proceed();
        String statementId = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
        Configuration configuration = mappedStatement.getConfiguration();
        String sql = getSql(boundSql, parameterObject, configuration);
        long end = System.currentTimeMillis();
        long timing = end - start;
        if(log.isInfoEnabled()){
            log.info("执行sql耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" );
            log.info("   "+sql);
        }
        return result;
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {
    }

    private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) {
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    sql = replacePlaceholder(sql, value);
                }
            }
        }
        return sql;
    }

    private String replacePlaceholder(String sql, Object propertyValue) {
        String result;
        if (propertyValue != null) {
            if (propertyValue instanceof String) {
                result = "'" + propertyValue + "'";
            } else if (propertyValue instanceof Date) {
                result = "'" + DATE_FORMAT.format(propertyValue) + "'";
            } else {
                result = propertyValue.toString();
            }
        } else {
            result = "null";
        }
        return sql.replaceFirst("\\?", Matcher.quoteReplacement(result));
    }
}

然后在配置文件 mybatis-config.xml 中添加配置

<plugins>
    <plugin interceptor="zj.cn.mybatis.plugin.SqlPrintInterceptor">plugin>
plugins>

六、逆向工程

一、添加配置文件

  1. 打开官网:MyBatis Generator
  2. pom.xml 文件中添加配置
    MyBatis01_第9张图片
 <project ...>
     ...
     <build>
       ...
       <plugins>
        ...
        <plugin>
          <groupId>org.mybatis.generatorgroupId>
          <artifactId>mybatis-generator-maven-pluginartifactId>
          <version>1.3.7version>
        plugin>
        ...
      plugins>
      ...
    build>
    ...
  project>

除了要增加官方文档
3. 添加配置文件
MyBatis01_第10张图片
注意:打开官方文档:Datebase Specific information for MySql
MyBatis01_第11张图片上面的英文文档翻译过来就是:
如果您使用的是Connector / J的8.x版,您可能会注意到生成器尝试为MySql信息模式(sys,information_schema,performance_schema等)中的表生成代码。这可能不是您想要的! 要禁用此行为,请将属性“nullCatalogMeansCurrent = true”添加到JDBC。

 <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/my_schema"
            userId="my_user" password="my_password">
        
    jdbcConnection>

本人使用的mysql的数据库版本为8,连带使用 mysql-connector-java.version:8.0.12,所以配置文件中需要添加以上那一段。



<generatorConfiguration>
    <context id="mybatisTables" targetRuntime="MyBatis3">
        
        <commentGenerator>
            <property name="suppressAllComments" value="false"/>
            
        commentGenerator>

        
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/zj_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT"
                        userId="root"
                        password="123456">
            
            <property name="nullCatalogMeansCurrent" value="true"/>
        jdbcConnection>
        
        <javaTypeResolver>
            
            <property name="forceBigDecimals" value="false"/>
        javaTypeResolver>
        
        <javaModelGenerator targetPackage="zj.cn.generator.pojo" targetProject="${user.dir}\src\main\java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        javaModelGenerator>
        
        <sqlMapGenerator targetPackage="mybatis" targetProject="${user.dir}\src\main\resources">
            <property name="enableSubPackages" value="true"/>
        sqlMapGenerator>
        
        <javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="zj.cn.generator.mapper"
                             targetProject="${user.dir}\src\main\java">
            <property name="enableSubPackages" value="true"/>
        javaClientGenerator>
        
        
        
        <table schema="zj_mybatis" tableName="user" domainObjectName="User">
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="ID" sqlStatement="Mysql" identity="true"/>
            <columnOverride column="DATE_FIELD" property="startDate"/>
            <ignoreColumn column="FRED"/>
            <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR"/>
        table>
    context>
generatorConfiguration>

二、执行命令:mvn mybatis-generator:generate

  1. 执行命令生成 Mapper 和 POJO
    打开官方文档,执行:mvn mybatis-generator:generate
    MyBatis01_第12张图片
    最终生成的代码如下图:
    MyBatis01_第13张图片

这里介绍三种方法执行,

  • 第一种方法:
    MyBatis01_第14张图片
  • 第二种方法:
    MyBatis01_第15张图片
  • 第三种方法:
    MyBatis01_第16张图片
    MyBatis01_第17张图片

三、javaClientGenerator

以上配置文件会生成注解形式(MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO 为数据库中的记录)的 Mapper 和 POJO
打开官方文档javaClientGenerator,介绍了几种方式,如下图:
MyBatis01_第18张图片

将以下这段配置,


        <javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="zj.cn.generator.mapper"
                             targetProject="${user.dir}\src\main\java">
            <property name="enableSubPackages" value="true"/>
        javaClientGenerator>

改成一下形式,就会生成xml形式 Mapper 和 POJO


        <javaClientGenerator type="XMLMAPPER" targetPackage="zj.cn.generator.mapper"
                             targetProject="${user.dir}\src\main\java">
            <property name="enableSubPackages" value="true"/>
        javaClientGenerator>

MyBatis01_第19张图片

四、测试

测试生成的mapper 和pojo时需要注意,字段desc是关键字,所以在测试时需要修改生成的sql语句,加上键盘左上角Esc下面的那个字符 ` ,例如:

select id, username, age, phone, `desc` from user where id = 1;

以下为本人的源码:
链接: https://pan.baidu.com/s/1hMaUf20F65pyuWBxt0cfNA 提取码: 85xv 复制这段内容后打开百度网盘手机App,操作更方便哦

你可能感兴趣的:(MyBatis源码学习)