逆向工程
mybatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml、mapper.java、po…)。一般在开发中,常用的逆向工程方式是通过数据库的表生成代码。
生成逆向工程需要用到 MyBatis Generator (MBG), MBG是MyBatis和iBATIS的代码生成器,它将为所有版本的MyBatis以及版本2.2.0之后的iBATIS版本生成代码。MBG对简单CRUD(增删改查)的大部分数据库操作产生重大影响。但是您仍然需要为连接查询或存储过程手动编写SQL和对象代码。
生成逆向工程
首先需要引入MyBatis-generator所需要的jar包。
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
下面通过官网的 quick start 教程生成一个简单的逆向工程。
在工程下创建 MyBatis Generator 的配置文件,其中包含如下配置:
-
<jdbcConnection>
数据库连接信息 -
<javaModelGenerator>
java模型生成(指定java Bean 生成的位置) -
<sqlMapGenerator>
指定sql映射文件生成的位置 -
<javaClientGenerator>
指定dao接口生成的位置,Mapper接口 -
<table>
指定每个表的生成策略
以上选项的具体的设定都可以在官网相关文档中 XML Configuration Reference
里面学习。
官网给我们举了一个简单的例子,可以参考它完成我们的配置。
<?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>
//表示它要导入的类
<classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
//配置数据库连接信息,这些需要自己配
<context id="DB2Tables" targetRuntime="MyBatis3">
<jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
connectionURL="jdbc:db2:TEST"
userId="db2admin"
password="db2admin">
</jdbcConnection>
//java类型解析
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
//ava模型生成(指定java Bean 生成的位置)
<javaModelGenerator targetPackage="test.model" //指定生位置(文件夹)
targetProject="\MBGTestProject\src"> //指定在那个工程下生成
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
//指定sql映射文件生成的位置
<sqlMapGenerator targetPackage="test.xml" //指定生位置(文件夹)
targetProject="\MBGTestProject\src"> //指定在那个工程下生成
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
//指定dao接口生成的位置,Mapper接口
<javaClientGenerator type="XMLMAPPER" targetPackage="test.dao"
targetProject="\MBGTestProject\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
//指定每个表的生成策略(具体生成策略在官网查看)
<table tableName="book" domainObjectName="Books" ></table>
<table tableName="papers" domainObjectName="Papers" ></table>
</context>
</generatorConfiguration>
现在我们生成了配置文件,接下来通过逆向工程生成相应的javaBean 和配置文件 。在官网的 Running MyBatis Generator
下提供了以下几种方案,现在我们使用Java生成逆向工程。
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MbjTest {
public static void main(String[] args) throws IOException, XMLParserException, SQLException, InterruptedException, InvalidConfigurationException {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbj.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);
}
}
假如我有三张表格分别为book, ticket, user,现在通过上面步骤生成一个简单的逆向工程。如下结构
MyBatis逆向工程类解析
我们表book为例,分析逆向工程生成的Book类, BookExample类,BookMapper以及生成的配置文件BookMapper.xml。
Book类就是根据数据库表应用ORM思想产生对应的属性以及get set方法,这里不再赘述,如下:
public class Book {
private Integer id;
private String name;
private String author;
private String price;
private Integer status;
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 == null ? null : name.trim();
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author == null ? null : author.trim();
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price == null ? null : price.trim();
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", price='" + price + '\'' +
", status=" + status +
'}';
}
}
BookMapper类为逆向工程相对应的查询方法,与BookMapper.xml相对应:
public interface BookMapper {
long countByExample(BookExample example);
int deleteByExample(BookExample example);
//按照主键删除
int deleteByPrimaryKey(Integer id);
//插入
int insert(Book record);
//选择性插入
int insertSelective(Book record);
//按照条件查询
List<Book> selectByExample(BookExample example);
//按照主键查询
Book selectByPrimaryKey(Integer id);
/*
按照条件选择性更新
第一个参数 是要修改的部分值组成的对象,其中有些属性为null则表示该项不修改。
第二个参数 是一个对应的查询条件的类, 通过这个类可以实现 order by 和一部分的where 条件
*/
int updateByExampleSelective(@Param("record") Book record, @Param("example") BookExample example);
//按照条件更新
int updateByExample(@Param("record") Book record, @Param("example") BookExample example);
//按照主键选择性更新
int updateByPrimaryKeySelective(Book record);
//按照主键更新
int updateByPrimaryKey(Book record);
}
下面查看 BookExample类,example类与实体类对应,是根据example根据Book类的属性设定相应的方法用作动态查询, 它可以使我们在查询的过程中添加各种复杂的筛选条件 如 where
、order by
等:
package com.zhangbing.bean;
import java.util.ArrayList;
import java.util.List;
public class BookExample {
//指定按照某个字段进行升序还是降序:字段+空格+asc(desc)
protected String orderByClause;
//去除重复:true是选择不重复记录,false,反之
protected boolean distinct;
//自定义查询条件
protected List<Criteria> oredCriteria;
public BookExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
//生成 Criteria 类的方法
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
//定义
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
// 添加字段xxx为null的条件
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
//添加字段xxx不为null的条件
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
//添加xxx字段等于value条件
public Criteria andIdEqualTo(Integer value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
//添加xxx字段不等于value条件
public Criteria andIdNotEqualTo(Integer value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
//添加xxx字段大于value条件
public Criteria andIdGreaterThan(Integer value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
//添加xxx字段大于等于value条件
public Criteria andIdGreaterThanOrEqualTo(Integer value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
//添加xxx字段小于value条件
public Criteria andIdLessThan(Integer value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
//添加xxx字段小于等于value条件
public Criteria andIdLessThanOrEqualTo(Integer value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
//添加xxx字段值在List
public Criteria andIdIn(List<Integer> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
//不添加xxx字段值在List
public Criteria andIdNotIn(List<Integer> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
//添加xxx字段值在之间
public Criteria andIdBetween(Integer value1, Integer value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
//添加xxx字段值不在之间
public Criteria andIdNotBetween(Integer value1, Integer value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
/*
下面为name字段以及其他属性的设置与上面相类似,这里不再赘述
*/
}
//内部Criteria类用来封装自定义查询条件
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}
测试生成的逆向工程
1、在resources下配置sqlmapconfig
<?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"> <!--约束-->
<!--mybatis的主配置文件-->
<configuration>
<!--配置环境-->
<properties resource="dbconfig.properties"></properties>
<environments default="mysql">
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="jdbc"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!--配置连接数据库的四个基本信息-->
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.jdbcUrl}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<mapper resource="Mapper/xml/BookMapper.xml"/>
<mapper resource="Mapper/xml/TicketMapper.xml"/>
<mapper resource="Mapper/xml/UserMapper.xml"/>
</mappers>
</configuration>
2、 测试CRUD
public class MyBatisTest {
SqlSession session;
InputStream in;
BookMapper bookMapper;
Book book;
@Before
public void init() throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
session = factory.openSession();
bookMapper = session.getMapper(BookMapper.class);
}
@After
public void destory() throws Exception{
session.close();
in.close();
}
/*
* 测试插入数据
* */
@Test
public void testCreate(){
Book book = new Book();
book.setId(2);
book.setAuthor("周志华");
book.setName("机器学习");
book.setPrice("88");
book.setStatus(0);
bookMapper.insert(book);
session.commit();
}
/*
* 测试读取数据
* */
@Test
public void testRead(){
BookExample bookExample = new BookExample();
bookExample.setOrderByClause("id desc");
bookExample.setDistinct(false);
BookExample.Criteria criteria = bookExample.createCriteria();
criteria.andIdEqualTo(1);
List<Book> books = bookMapper.selectByExample(bookExample);
for(Book b : books){
System.out.println(b);
}
}
/*
* 测试更新数据 updateByExampleSelective updateByExample
* updateByPrimaryKeySelective updateByPrimaryKey 四个方法
* */
@Test
public void testUpdateByExampleSelective(){
Book newbook = new Book(1, "高性能MySql", "Baron Scbwart", "99", 1);
BookExample bookExample = new BookExample();
BookExample.Criteria criteria = bookExample.createCriteria();
criteria.andIdEqualTo(1);
criteria.andNameLike("%高%");
bookMapper.updateByExampleSelective(newbook, bookExample);
session.commit();
}
}
这样就生成了一个简单的逆向工程。