2

本章主要介绍的是MyBatis的基础应用和源码涉及的相关等,主要包含的内容有MyBatis的简介、反射、动态代理(包含JDK代理和cglib代理)、MyBatis使用和代码生成器等。

1.1 MyBatis简介

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

关于MyBatis相关的信息,大家可以参考如下:
MyBatis官网: http://www.mybatis.org/
MyBatis文档: http://www.mybatis.org/mybati...
MyBatis源码地址: https://github.com/mybatis/my...

1.2 反射

1.2.1 反射简介

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

1.2.2 反射的应用场景

从实用的角度看,笔者认为有如下几个场景?大家可以做一个思考。

(1) 逆向代码,例如反编译;

(2) 与注解结合的框架,现在有不少java框架都采用注解的方式,例如Spring既可以通过注解管理事务又可以通过XML方式管理事务;

(3) 插件系统, 程序设计了加载新JAR的功能,陌生JAR文件在程序运行时加入,被编译成class文件,通过反射机制加载进内存;

(4) 配置文件中的休眠class类, 一个程序有许许多多功能,不可能相对应的class文件一次性全部加载进内存,只能是加载进维持程序运行的基本class,其余功能只有等用的时候,采用触发机制,通过xml配置文件获取类名等信息,然后通过反射机制加载相关class进内存。

1.2.3 反射实例

代码如下:

package cn.reflect;

import java.lang.reflect.Method;

public class ReflectService {

    /**
     * 测试方法
     * @param name
     */
    public void testReflect(String name) {
        System.out.println("hello:"+name);
    }
    
    /**
     * 测试入口
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        
        /**
         * 通过反射创建ReflectService对象
         */
        Object service = Class.forName(ReflectService.class.getName()).newInstance();
        
        /**
         * 获取服务方法
         */
        Method method = service.getClass().getMethod("testReflect", String.class);
        
        method.invoke(service, "张三");
        
        
    }
    
}

1.2.4反射的优缺点

反射在给我们带来极大的便利的同时,也带给我们潜在的危害。这也就是有利也有弊。

反射的优点:

反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

反射的缺点:

(1)性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

(2)使用反射会模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

1.3 动态代理

1.3.1 动态代理简介

动态代理有两种方式,一种是JDK的代理,另外一种是cglib代理。
它们之间的区别是,JDK是代理接口,cglib代理类。
换言之,一个是接口方式,一个是类的方式,类的方式通常表现为继承。

1.3.2 JDK代理应用实例

步骤如下:

(1)编写接口类

HelloService.java

package cn.reflect;
public interface HelloService {

    public void sayHello(String name);
}

(2)编写实现类
HelloServiceImpl.java

package cn.reflect;

public class HelloServiceImpl implements HelloService {

    public void sayHello(String name) {
        // TODO Auto-generated method stub
        System.err.println("hello:"+name);
    }

}

(3)编写代理类

HelloServiceProxy.java

package cn.reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HelloServiceProxy implements InvocationHandler {
    
    /**
     * 真实服务对象
     */
    private Object target;
    
    public Object bind(Object target){
        this.target=target;
        /**
         * 取得代理对象
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);//jdk代理对象需要提供接口
        
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        
        System.out.println("我是JDK动态代理对象");
        
        Object result = null;
        
        /**
         * 反射方法调用前
         */
        System.out.println("我准备说hello");
        
        /**
         * 执行方法,相当于调用HelloServiceImpl中的sayHello方法
         */
        result = method.invoke(target, args);
        
        /**
         * 反射方法后调用
         */
        System.out.println("我说过hello了");
        
        return result;

    }

}

(4)编写运行测试类
HelloServiceMain.java

package cn.reflect;

public class HelloServiceMain {
    public static void main(String[] args) {
        
        HelloServiceProxy helloHandle = new HelloServiceProxy();
    
        HelloService proxy = (HelloService) helloHandle.bind(new HelloServiceImpl());
        proxy.sayHello("张三");
        
    }
}

1.3.3 cglib代理应用实例

JDK提供的动态代理存在缺陷,必须提供接口才能使用,没有接口就不能使用,为了克服这个缺陷,我们可以采用cglib代理,它是一种流行的动态代理。

步骤如下:

(1) 导入maven依赖

       <dependency>
         <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
       </dependency>

(2) 编写运行测试类
HelloServiceCgLib.java

package cn.reflect;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class HelloServiceCgLib implements MethodInterceptor{
    private Object target;

    /**
     * 创建代理对象
     */
    public Object getInstance(Object target) {
        
        this.target=target;
        Enhancer enHancer = new Enhancer();
        enHancer.setSuperclass(this.target.getClass());
        enHancer.setCallback(this);
        return enHancer.create();
        
    }
    
    
    public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("我是cglib代理对象");
        Object returnObj = proxy.invoke(obj, arg);
        
        /**
         * 反射方法前调用
         */
        System.out.println("我准备说hello");
        
        /**
         * 反射方法后调用
         */
        System.out.println("我说过hello了");
        
        return returnObj;
        
        
    }
    
    
}

1.4 MyBatis使用

1.4.1 导入依赖

由于采用的是maven,只需引入maven对应的依赖即可,通常情况下,只要maven依赖导入准确,一般情况下很少会出现因为依赖冲突的问题导致项目运行失败。

pom.xml

<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>cn.youcong.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>


  </dependencies>
</project>

1.4.2 准备SQL脚本

CREATE TABLE `user` (
  `user_id` int(8) NOT NULL AUTO_INCREMENT COMMENT '用户主键',
  `login_code` varchar(20) NOT NULL COMMENT '用户编码(登录账户) 手机号 邮箱号',
  `user_name` varchar(20) NOT NULL COMMENT '用户名',
  `password` varchar(40) NOT NULL COMMENT '密码',
  `sex` int(2) NOT NULL COMMENT '性别',
  `identity_card` varchar(20) DEFAULT NULL COMMENT '身份证',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `create_by` varchar(10) NOT NULL COMMENT '创建人',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `update_by` varchar(10) NOT NULL COMMENT '更新人',
  `status` int(2) NOT NULL DEFAULT '0' COMMENT '状态:0注册新用户 1邮件认证用户 2管理员 3黑名单',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

1.4.3 编写实体

package com.blog.entity;

import java.io.Serializable;


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


public class User{

    private static final long serialVersionUID = 1L;

    /**
     * 用户主键
     */
    private Integer userId;
    /**
     * 用户编码(登录账户) 手机号 邮箱号
     */
    private String loginCode;
    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String password;
    /**
     * 性别
     */
    private Integer sex;
    /**
     * 身份证
     */
    private String identityCard;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 创建人
     */

    private String createBy;
    /**
     * 更新时间
 */
    private Date updateTime;
    /**
     * 更新人
     */
    private String updateBy;
    /**
     * 状态:0注册新用户 1邮件认证用户 2管理员 3黑名单
     */
    private Integer status;


    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public static long getSerialversionuid() {
        return serialVersionUID;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getLoginCode() {
        return loginCode;
    }

    public void setLoginCode(String loginCode) {
        this.loginCode = loginCode;
    }

    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 Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public String getIdentityCard() {
        return identityCard;
    }

    public void setIdentityCard(String identityCard) {
        this.identityCard = identityCard;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }  
}

1.4.4 编写数据访问层及其对应的XML文件

package com.blog.dao;

import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import com.blog.entity.User;

public interface UserDao {
    @Select("select * from `user` where user_id=#{userId}")
    @Results(@Result(property="userName",column="user_name"))
    User selectOne(int userId);

}

@Select是MyBatis的注解写法,当字段名和属性名一致时,可以直接@Select不需要@Results,@Results的作用就是因为实体属性与字段不一致,为了获取查询结果,必须要这样。

当然了你也可以不写注解,直接在对应的UserDao.xml写,如果是UserDao.xml里面写的话,就会变成这样

package com.blog.dao;
 
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
 
import com.blog.entity.User;
 
public interface UserDao {
 
    User selectOne(int userId);
 
}

需要在UserDao.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">
<mapper namespace="com.blog.dao.UserDao">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.blog.entity.User">
        <id column="user_id" property="userId" />
        <result column="login_code" property="loginCode" />
        <result column="user_name" property="userName" />
        <result column="password" property="password" />
        <result column="sex" property="sex" />
        <result column="identity_card" property="identityCard" />
        <result column="create_time" property="createTime" />
        <result column="create_by" property="createBy" />
        <result column="update_time" property="updateTime" />
        <result column="update_by" property="updateBy" />
        <result column="status" property="status" />
    </resultMap>

    <!-- 通用查询结果列 -->

    <sql id="Base_Column_List">
        user_id, login_code, user_name, password, sex, identity_card, create_time, create_by, update_time, update_by, status
    </sql>
 <select id="selectOne" resultMap="BaseResultMap"> select * from `user` where user_id=#{userId} </select> </mapper>


除了<select>标签之外,还有<insert>、<update>、<delete>,它们的作用分别是查、增、更、删。当然了,还有这里面可以<sql>,这个<sql>的作用就是为了复用重复列,省的重复编写代码冗余。如果要引用,写成这样既可

<!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        user_id, login_code, user_name, password, sex, identity_card, create_time, create_by, update_time, update_by, status
    </sql>
    
    <select id="selectOne" resultMap="BaseResultMap">
        select <include refid="Base_Column_List"/>
        from `user` where user_id=#{userId}
    </select>

MyBatis常用的两种写法,XML方式和注解方式,但是无论你采用哪种,对应的XML文件必须要存在。

其实<resultMap id="BaseResultMap" type="com.blog.entity.User"> 可以变成 <resultMap id="BaseResultMap" type="User">

前提必须要在mybatis-config.xml配置

<typeAliases>
    <typeAlias type="com.blog.entity.User" alias="User"/>
</typeAliases>

但是有人觉得,如果我的类有很多,岂不是要配置很多,太麻烦了,别怕,MyBatis已经为你想到了

<typeAliases>
    <package name="com.blog.entity"/>
</typeAliases>

这样配置就解决了重复配置的麻烦
其实除了这样,如果你想标新立异点,还可以再实体最上面加上@Alias注解

clipboard.png

这就是MyBatis的别名三种方式/策略。

1.4.5 编写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://127.0.0.1:3306/blog_test"/>
        <property name="username" value="root"/>
        <property name="password" value="1234"/>
      </dataSource>
    </environment>
  </environments>
   
  <mappers>
    <mapper resource="mybatis/mapping/UserDao.xml"/>
  </mappers>
</configuration>

mybatis-config.xml这个配置没多大用,坦白说。

因为后期与Spring整合由Spring来管理数据库连接池对象。

不过还是要稍微讲讲,以让读者达到开卷有益的目的或者是让没有学过的或者已经学过但是不知道的涨涨见识。

<environment id="development">表示我们默认使用development配置环境

<transactionManager type="JDBC"/> 采用JDBC的事务管理模式

<dataSource type="POOLED"> 数据库连接信息

<mappers> 映射器 通常一般映射XML文件

1.4.6 编写工具类

package com.blog.config;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class SqlSessionFactoryUtils {
    
private static SqlSessionFactory sqlSessionFactory = null;
    
    public static SqlSessionFactory getSqlSessionFactory() {
        InputStream is  = null;
        if(sqlSessionFactory==null) {
            
            String resource = "mybatis/mybatis-config.xml";
            try {
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource));
                return sqlSessionFactory;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }            
    
        }
    
        return sqlSessionFactory;
    }
        
}

说到上述代码,顺便谈谈MyBatis的核心组件。它的核心组件主要有这么几个,如下所示:

SqlSessionFactoryBuilder:它会根据配置信息或者代码来生成SqlSessionFactory;

SqlSessionFactory:依赖工厂生成SqlSession;

SqlSession:是一个即可发送SQL执行返回结果,也可以获取Mapper接口;

Sql Mapper:它是MyBatis的新设计组件,它是由一个Java接口和XML文件(或注解)构建,需要给出对应的SQL和映射规则。它负责发送SQL去执行并返回结果。

用一张图来表示它们之间的关系,如图:

clipboard.png

它们的生命周期在此稍微说一下:

(1)SqlSessionFacotoryBuilder
SqlSessionFacotoryBuilder是利用XML和Java代码获得资源来构建SqlSessionFactory的,通过它可以构建多个SqlSessionFactory,它的作用就是一个构建器,一旦我们构建了SqlSessionFactory,它的作用就完结,它就失去存在的意义。这时我们应该毫不犹豫的废弃它,将它回收。所以它的生命周期只存在方法局部,它的作用就是生成SqlSessionFactory。

(2)SqlSessionFactory的作用是创建SqlSession,而SqlSession就是一个会话,相当于JDBC中的Connection对象。每次应用程序需要访问数据库,我们就要通过SqlSessionFactory创建SqlSession,所以SqlSessionFactory应该在MyBatis应用的整个生命周期中。而如果我们多次创建同一个数据库的SqlSessionFactory,则每次创建SqlSessionFactory会打开更多的数据库连接资源,那么连接资源就很快会被耗尽。因此SqlSessionFactory的责任是唯一的,它的责任就是创建SqlSession,所以我们果断采用单例模式。如果采用多例,那么它对数据库连接的消耗是很大的,不利于我们统一管理。所以正确的做法是使得每个数据库只对应一个SqlSessionFactory,管理好数据库资源分配,避免过多的Connection被消耗。

(3)SqlSession
SqlSession是一个会话,相当于JDBC的一个Connection对象,它的生命周期应该是在请求数据库处理事务的过程中。它是一个线程不安全的对象,在涉及多线程的时候我们需要特别当心,操作数据库需要注意其隔离级别,数据库锁等高级特性。此外,每次创建的SqlSession都必须及时关闭它,它长期存在就会使数据库连接池的活动资源减少,对系统性能的影响很大。

(4)Mapper
Mapper是一个接口,而没有任何实现类,它的作用是发送SQL,然后返回我们需要的结果,或者执行SQL从而修改数据库的数据,因此它应该在一个SqlSession事务方法之内,是一个方法级别的东西。它就如同JDBC中的一条SQL语句的执行,它的最大范围和SqlSession是相同的。尽管我们想一直保存着Mapper,但是你会发现它很难控制,所以尽量在一个SqlSession事务的方法中使用它们,然后废弃掉。

MyBatis组件生命周期,如图:

clipboard.png

1.4.7 测试

package mybatis;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import com.blog.config.SqlSessionFactoryUtils;
import com.blog.dao.UserDao;
import com.blog.entity.User;

public class MyBatisTest {

    
    @Test
    public void testName() throws Exception {
          SqlSession sqlSession = null;
          sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
            
          UserDao userDao = sqlSession.getMapper(UserDao.class);
          
          User user = userDao.selectOne(1);
          System.out.println(user.getUserName());
    }
}



1.5 MyBatis代码生成器

MyBatis代码生成器,又称逆向工程。

关于逆向工程的优点和缺点,我觉得我还是要说说。

逆向工程的优点是:自动化生成实体类和对应的增删改查,效率相对于之前个人开发时一个个写增删改查要高的多

逆向工程的缺点是:xml中的sql语句加入了mybatis自身的动态sql和一大堆判断等,对于对动态sql不是十分熟练的人而言,以后再功能扩展上会很困难。

================
MyBatis代码生成器我分为两个,一个是动态web工程,另一个是现在比较流行的maven工程,本质上都是一样,只是项目管理jar包的方式不一样。

1.5.1动态web工程

(1)导包

clipboard.png

(2)新建generator.xml文件,进行配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        <property name="javaFileEncoding" value="UTF-8"/>
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/pms" userId="root"
            password="1234">
        </jdbcConnection>
        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 
            NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成model类的位置 -->
        <javaModelGenerator targetPackage="cn.pms.model"
            targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="mapper"
            targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="cn.pms.mapper"
            targetProject=".\src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
</javaClientGenerator>
    
     
     
     <!-- 指定数据库表 -->
        <table schema="" tableName="hotel" domainObjectName="Hotel"></table>
    </context>

</generatorConfiguration>

(3)测试

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorSqlmap {

    public void generator() throws Exception{

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("src/generatorConfig.xml"); 
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    } 
    public static void main(String[] args) throws Exception {
        try {
            GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
            generatorSqlmap.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

}

测试结果在控制台打印如下,表示成功

clipboard.png

1.5.2 maven工程

(1)导入maven依赖

<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>cn.mybatis.generator</groupId>
    <artifactId>mybatis-generator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
 
 
    <build>
         <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                    <version>3.3</version>
                </plugin>
                <plugin>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-maven-plugin</artifactId>
                    <version>1.3.2</version>
                    <dependencies>
                        <dependency>
                            <groupId>mysql</groupId>
                            <artifactId>mysql-connector-java</artifactId>
                            <version>5.1.35</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                         <!--配置文件的路径-->
                         <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                        <overwrite>true</overwrite>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
 
 
</project>

 

(2)在src/main/resource目录下新建配置文件generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="test" targetRuntime="MyBatis3">
        <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"></plugin>
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"></plugin>
        <commentGenerator>
            <!-- 这个元素用来去除指定生成的注释中是否包含生成的日期 false:表示保护 -->
            <!-- 如果生成日期,会造成即使修改一个字段,整个实体类所有属性都会发生变化,不利于版本控制,所以设置为true -->
            <property name="suppressDate" value="true" />
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--数据库链接URL,用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/blog" userId="root"
            password="1234">
        </jdbcConnection>
        <javaTypeResolver>
            <!-- This property is used to specify whether MyBatis Generator should
                force the use of java.math.BigDecimal for DECIMAL and NUMERIC fields, -->
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- 生成模型的包名和位置 -->
        <javaModelGenerator targetPackage="cn.blog.model"
            targetProject="target">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置 -->
        <sqlMapGenerator targetPackage="cn.blog.mapper"
            targetProject="target">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="cn.blog.mapper" implementationPackage="cn.blog.service.impl"
            targetProject="target">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
 
        <!-- 要生成哪些表 -->
        <table tableName="`post`" domainObjectName="Post"></table>
 
        <table tableName="`posttag`" domainObjectName="PostTag"></table>
 
        <table tableName="`tag`" domainObjectName="Tag"></table>
 
        <table tableName="`type`" domainObjectName="Type"></table>
 
 
        <table tableName="`typetag`" domainObjectName="typetag"></table>
 
 
    </context>
</generatorConfiguration>

(3)右击进入run as 点击maven build 如下图输入:mybatis-generator:generate

clipboard.png

运行结果如下,表示成功

clipboard.png

注意:运行成功后,直接是看不到生成的代码,还需要刷新一下(refresh)。

1.6 小结

通过上面的内容,我相信读者对于MyBatis已经有了大致的了解,通过相关的代码示例,我相信读者应该知道怎么使用MyBatis了。当然了,这仅仅只是MyBatis的冰山一角,MyBatis的特性还有很多。不过我之所以讲MyBatis也是为了后续读者更好理解MyBatis-plus。

本文主要参考我个人的博客园中的MyBatis系列相关的,可以说这篇文章是之前MyBatis相关教程不太完善的补充。希望能够帮助到大家。

最后,如需转载本文,请附源地址,谢谢合作。


youcongtech
128 声望15 粉丝

我不仅仅喜欢编程,而且还喜欢读书和旅行还有运动。