在学习与工作中,大家一定经常做 CRUD,也就是增删改查,而若要对一个表进行 CRUD 的操作,那么必须创建实体类、Dao 层接口、Dao 层实现类、SQL 语句。
如果你的项目使用了 MyBatis 的话,则还需要写一大堆与映射文件,作为一名菜鸟的我,简单的实体类不想写,自己设计的 Dao 接口功能不完善,最后还被复杂的映射文件整的晕头转向。
最终我使用了 MyBatis 逆向工程,才发现原本只会 CRUD 的我,又被冒犯到了,本来我也就只会创建几个实体类,实现几个简单的增删改查,写几个映射文件,最终发现,这些工作又被 MyBatis 逆向工程给抢了,虽然饭碗丢了,但还是觉得学会 MyBatis 逆向工程是真的香。
学习一门技术,最好的方式就是上官网,虽然官网的英文,我大部分都是看不懂的(但是咱有翻译呀!)。
官网:
http://mybatis.org/generator/index.html
经过了一个下午的摸索,发现我这英语水平,看官网几乎不太可能完全看得懂的,所以最后我还是在度娘上找了许多各位前辈的经验分享,使用 MyBatis 逆向工程大致流程如下:
链接:https://pan.baidu.com/s/1Z9o8JuyRga-Q22TzPvztwg
提取码:643c
-- 创建数据表(该表所属数据库为 haicoder_db)
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(20),
sex VARCHAR(5),
age INT,
address VARCHAR(30),
email VARCHAR(50),
phone VARCHAR(30),
birthday DATE
)
-- 插入一条记录
INSERT INTO student(`NAME`,sex,age,address,email,phone,birthday) VALUES( '张三','男',13,'广西','234433@qq.com','13223324535','1997-09-14');
创建Maven项目
新建模块,如下图:
选择 Maven,点击 Next,如下图:
填入项目信息,创建项目,如下图:
项目结构,如下图:
环境配置
MyBatis Generator 包括一个 Maven 插件,用于集成到 Maven 构建中,需要进行以下配置,如下图:
pom 文件:
<?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>net.haicoder</groupId>
<artifactId>mybatis_generate</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mybatis逆向工程核心包-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--mybatis核心包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
<!--集成到Maven构建-->
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>src/main/resources/mybatis-generator-config.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
</project>
jdbc.properties 文件:
jdbc.path=D:/tools/maven/repository/mysql/mysql-connector-java/5.1.6/mysql-connector-java-5.1.6.jar
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/haicoder_db
jdbc.username=root
jdbc.password=root
mybatis-generator-config.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>
<!--导入属性配置-->
<properties resource="jdbc.properties"></properties>
<!--jdbc驱动-->
<classPathEntry location="${jdbc.path}"/>
<context id="context" targetRuntime="MyBatis3">
<!--是否去除自动生成的注释-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
</commentGenerator>
<!--数据库连接的信息-->
<jdbcConnection driverClass="${jdbc.driver}"
connectionURL="${jdbc.url}"
userId="${jdbc.username}"
password="${jdbc.password}"/>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--
targetPackage:实体类包名
targetProject:文件地址
-->
<javaModelGenerator targetPackage="net.haicoder.domain" targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--
targetPackage:Mapper映射文件包名
targetProject:文件地址
-->
<sqlMapGenerator targetPackage="net.haicoder.dao" targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\resources">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--type="XMLMAPPER":生成XML映射文件和独立的持久层接口-->
<javaClientGenerator targetPackage="net.haicoder.dao"
targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\java" type="XMLMAPPER">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--
schema: 数据库名称
tableName: 生成的表名称
domainObjectName: 实体类名称
mapperName: Dao接口Dao映射文件名称
-->
<table schema="haicoder_db" tableName="student" domainObjectName="Student" mapperName="StudentDao"
enableCountByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" enableUpdateByExample="false"/>
</context>
</generatorConfiguration>
配置文件解析
通用配置部分,不进行赘述,如下图:
自定义配置部分,配置部分解释如下:
标签
属性
作用
javaModelGenerator
targetPackage
实体类生成后所属的包名
javaModelGenerator
targetProject
实体类生成后的真实地址(建议使用绝对路径)
sqlMapGenerator
targetPackage
实体类映射文件生成后所属的包名
sqlMapGenerator
targetProject
实体类映射文件生成后的真实地址(建议使用绝对路径)
javaClientGenerator
type=“XMLMAPPER”
生成 XML 映射文件和独立的持久层接口
table
schema
数据库名称
table
tableName
数据表名称
table
domainObjectName
实体类名称
table
mapperName
Dao 接口,Dao 映射文件名称
代码实现
测试类:
package net.haicoder;
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;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class MyBatisGeneratorTest {
public void generator() throws Exception {
List<String> warnings = new ArrayList<>();
boolean overwrite = true;
// 指定逆向工程配置文件
InputStream in = MyBatisGeneratorTest.class.getClassLoader().getResourceAsStream("mybatis-generator-config.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(in);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
in.close();
}
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)\n");
try {
MyBatisGeneratorTest myBatisGenerator = new MyBatisGeneratorTest();
myBatisGenerator.generator();
System.out.println("生成完毕!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行 MyBatisGeneratorTest 类,运行结果如下:
此时发现已经生成了实体类、Dao接口、实体映射文件,如下图:
增删改查
前期准备
为了测试学生表的增删改查操作,此处添加 junit 依赖,pom 文件修改如下:
<?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>net.haicoder</groupId>
<artifactId>mybatis_generate</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mybatis逆向工程核心包-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--mybatis核心包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--Maven的目标与执行-->
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>src/main/resources/mybatis-generator-config.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
</project>
创建 MyBatis 核心配置文件,代码如下:
<?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>
<settings>
<!--在控制台显示SQL语句-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--定义实体类别名-->
<typeAliases>
<package name="net.haicoder.domain"/>
</typeAliases>
<environments default="default">
<!--环境变量-->
<environment id="default">
<!--事务管理器-->
<transactionManager type="JDBC"/>
<!--数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/haicoder_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--加载其它映射文件-->
<mappers>
<package name="net.haicoder.dao"/>
</mappers>
</configuration>
测试代码
package net.haicoder.test;
import net.haicoder.dao.StudentDao;
import net.haicoder.domain.Student;
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 org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
/**
* 测试类
*/
public class TestStudentMapper {
// 只需要创建一次
private static SqlSessionFactory factory;
// 声明会话对象
private SqlSession session;
// 声明DAO接口
private StudentDao studentDao;
// 静态方法,类加载完毕以后执行1次
@BeforeClass
public static void init() throws IOException {
// 创建核心配置文件的输入流
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 创建工厂建造类
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(resourceAsStream);
}
@Before
public void begin() {
session = factory.openSession();
//通过会话得到代理对象
studentDao = session.getMapper(StudentDao.class);
}
// 根据主键查询学生信息
@Test
public void testSelectByPrimaryKey() {
System.out.println("嗨客网(www.haicoder.net)\n");
Student student = studentDao.selectByPrimaryKey(1);
System.out.println("【学生信息】:" + student + "\n");
}
// 添加学生信息
@Test
public void testInsert() {
System.out.println("嗨客网(www.haicoder.net)\n");
Student student = new Student();
student.setId(null);
student.setName("李四");
student.setSex("男");
student.setAge(20);
student.setAddress("上海");
student.setEmail("13343328@haicoder.net");
student.setPhone("13332247432");
studentDao.insert(student);
System.out.println("添加成功!" );
}
// 选择性添加学生信息
@Test
public void testInsertSelective() {
System.out.println("嗨客网(www.haicoder.net)\n");
Student student = new Student();
student.setName("王五");
student.setSex("男");
student.setAge(20);
student.setAddress("上海");
student.setEmail("13343328@haicoder.net");
studentDao.insertSelective(student);
System.out.println("添加成功!" );
}
// 根据主键更新学生信息
@Test
public void testUpdateByPrimaryKey() {
System.out.println("嗨客网(www.haicoder.net)\n");
Student student = new Student();
student.setId(3);
student.setName("王五");
student.setSex("男");
student.setAge(25);
student.setPhone("1323423234");
student.setBirthday(new Date());
studentDao.updateByPrimaryKey(student);
System.out.println("更新成功!" );
}
// 根据主键选择性更新学生信息
@Test
public void testUpdateByPrimaryKeySelective() {
System.out.println("嗨客网(www.haicoder.net)\n");
Student student = new Student();
student.setId(3);
student.setAddress("上海");
student.setEmail("13343328@haicoder.net");
studentDao.updateByPrimaryKeySelective(student);
System.out.println("更新成功!" );
}
@After
public void end() {
// 手动提交事务
session.commit();
session.close();
}
}
根据主键查询
测试前,查看数据库数据,如下图:
根据主键查询数据,运行结果如下图:
添加学生信息
添加学生所有信息,运行结果如下图:
添加成功后,查看数据库,如下图:
选择性添加学生信息(常用),运行结果如下图:
添加成功后,查看数据库,如下图:
观察上方两种添加方式的 SQL 语句,可以得出以下结论:
insert
:所有字段添加,若该字段无数据,则会自动补 NULL
,然后存放数据。
insertSelective
:只添加有数据的字段,若该字段无数据,则会存放该字段的默认值。
- 因此,
insertSelective
比 insert
要更加灵活。
根据主键更新
根据主键更新学生所有信息,运行结果如下图:
更新成功后,查看数据库变化,如下图:
根据主键更新学生部分信息(常用),运行结果如下图:
更新成功后,查看数据库,如下图:
观察上方两种更新方式的 SQL 语句,可以得出以下结论:
updateByPrimaryKey
:所有字段更新,若该字段无数据,则会自动更新为 NULL
,然后更新数据。(可能会造成原本数据丢失)
updateByPrimaryKeySelective
:只更新有数据的字段,若该字段无数据,则不会进行更新。
- 因此,
updateByPrimaryKeySelective
比 updateByPrimaryKey
要更加灵活。
条件查询
不会吧,不会有人以为到这里已经要结束了吧?那你可真的小看 MyBatis 逆向工程了。看了上面的案例后,你可能觉得少了点啥,但一时又不知道少了什。试想一下,我们平时查询时,还有根据性别查询学生,查询姓张的学生,查询未成年的学生等等,反观上面案例只有剩一个主键查询了,难道是作者忘记设计了?下面开始演示根据条件查询学生信息。(试想一下,我们平时是不是根据条件查询才是最多的操作,所以这点很重要,请耐心读完!)
前期准备
为了使用条件查询,我们需要修改配置文件 mybatis-generator-config.xml
,如下图:
整天想偷懒的我,同样理解你们,C、V 大法操作起来,代码如下:
<?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>
<!--导入属性配置-->
<properties resource="jdbc.properties"></properties>
<!--jdbc驱动-->
<classPathEntry location="${jdbc.path}"/>
<context id="context" targetRuntime="MyBatis3">
<!--自动生成toString-->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<!--是否去除自动生成的注释-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
</commentGenerator>
<!--数据库连接的信息-->
<jdbcConnection driverClass="${jdbc.driver}"
connectionURL="${jdbc.url}"
userId="${jdbc.username}"
password="${jdbc.password}"/>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--
targetPackage:实体类包名
targetProject:文件地址
-->
<javaModelGenerator targetPackage="net.haicoder.domain" targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--
targetPackage:Mapper映射文件包名
targetProject:文件地址
-->
<sqlMapGenerator targetPackage="net.haicoder.dao" targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\resources">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--type="XMLMAPPER":生成XML映射文件和独立的持久层接口-->
<javaClientGenerator targetPackage="net.haicoder.dao"
targetProject="E:\workspace\haicoder_javaee\mybatis_generate\src\main\java" type="XMLMAPPER">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!--
schema: 数据库名称
tableName: 生成的表名称
domainObjectName: 实体类名称
mapperName: Dao接口Dao映射文件名称
-->
<table schema="haicoder_db" tableName="student" domainObjectName="Student" mapperName="StudentDao"
enableCountByExample="false" enableDeleteByExample="false"
enableSelectByExample="true" enableUpdateByExample="false"/>
</context>
</generatorConfiguration>
此时需要重新再生成一次代码,如下图:
生成之后,你一定充满了疑问,怎么 StudentDao.xml 全都是红色的?难道显卡坏掉了?当然不是,因为再次生成,它是直接继续在原本的实体类映射文件中生成的,因此出现了大量的重复代码,注意:重新生成前,需要把原本的实体映射文件删除,再重新生成,再次执行 MyBatisGeneratorTest
,结果如下:
生成成功后,新的项目结构如下图:
此时发现目录中比原本的多了个类,这个类就是帮助我们条件查询的。
测试代码
package net.haicoder.test;
import net.haicoder.dao.StudentDao;
import net.haicoder.domain.Student;
import net.haicoder.domain.StudentExample;
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 org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 测试类
*/
public class TestStudentMapper {
// 只需要创建一次
private static SqlSessionFactory factory;
// 声明会话对象
private SqlSession session;
// 声明DAO接口
private StudentDao studentDao;
// 静态方法,类加载完毕以后执行1次
@BeforeClass
public static void init() throws IOException {
// 创建核心配置文件的输入流
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
// 创建工厂建造类
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(resourceAsStream);
}
@Before
public void begin() {
session = factory.openSession();
//通过会话得到代理对象
studentDao = session.getMapper(StudentDao.class);
}
// 查询所有学生信息
@Test
public void testFindAllStudent() {
System.out.println("嗨客网(www.haicoder.net)\n");
StudentExample studentExample = new StudentExample();
List<Student> studentList = studentDao.selectByExample(studentExample);
for(Student student:studentList){
System.out.println(student);
}
}
// 查询来自上海的学生
@Test
public void testFindStudentByAddress() {
System.out.println("嗨客网(www.haicoder.net)\n");
StudentExample studentExample = new StudentExample();
// 条件:address='上海'
studentExample.createCriteria().andAddressEqualTo("上海");
List<Student> studentList = studentDao.selectByExample(studentExample);
for(Student student:studentList){
System.out.println(student);
}
}
// 查询姓张的学生
@Test
public void testFindStudentBySurname() {
System.out.println("嗨客网(www.haicoder.net)\n");
StudentExample studentExample = new StudentExample();
// 条件:name like '%张%'
studentExample.createCriteria().andNameLike("%张%");
List<Student> studentList = studentDao.selectByExample(studentExample);
for(Student student:studentList){
System.out.println(student);
}
}
// 按照年龄倒叙查询学生
@Test
public void testFindStudentByAge() {
System.out.println("嗨客网(www.haicoder.net)\n");
StudentExample studentExample = new StudentExample();
// 条件:order by age desc
studentExample.setOrderByClause("age desc");
List<Student> studentList = studentDao.selectByExample(studentExample);
for(Student student:studentList){
System.out.println(student);
}
}
@After
public void end() {
// 手动提交事务
session.commit();
session.close();
}
}
运行结果
查询所有学生信息,运行结果如下:
查询来自上海的学生,运行结果如下:
查询姓张的学生,运行结果如下:
按照年龄倒叙查询学生,运行结果如下:
总结
以上案例运用了 MyBatis 逆向工程的技术,生成了实体类、Dao 接口、实体类映射文件,并演示了简单的增删改查以及条件查询等操作。