Mybatis在我上个项目中结合spring+springMVC框架的SSM架构中有用到,Mybatis作为一个半自动化的ORM框架,在编程的难度对比上我觉得比Hibernate的性能要好,对简单数据做操作时当然是Hibernate更为方便因为不用写SQL语句,但是在操作的自由性和性能的比较上我觉得mybatis要更好些,但是我最近又系统学习了spring-data-jpa框架,我觉得这个框架用来写数据交互真的要比Mybatis或者Hibernate爽太多了。。。(个人意见,可能有一部分是因为结合了Springboot)
mybatis是一个半自动化的orm框架,所谓半自动化就是mybaitis只支持数据库查出的数据映射到pojo类上,而实体到数据库的映射需要自己编写sql语句实现,相较于hibernate这种完全自动化的框架我更喜欢mybatis,mybatis非常灵活,可以随心所欲的编写自己的sql语句来实现复杂的数据库操作,还会有一种畅酣淋漓的编写sql语句的潇洒感,但是以前的mybaits需要一大堆的配置文件,以及各种mapper和dao和实体的关联,导致使用mybatis还是不够简洁,后来mybatis也发现了这个弊端,开发了mybatis generator工具来自动化生成实体类、mapper配置文件、dao层代码来减轻开发工作量,在后期也是实现了抛弃mapper配置文件基于注解的开发模式,直到现在,mybatis看spring boot这么火热,也开发了一套基于spring boot的模式:mybatis-spring-boot-starter。
spring boot简约轻巧的风格正在逐渐被越来越多的厂商及开发者所认可,包括阿里的开源RPC框架dubbo也准备开发一套对spring boot应用的支持(dubbo-spring-boot-starter启动配置模块)
在springboot框架下开发项目很爽,因为需要集成的基本单元已经帮你集成好了,因为使用了java配置的原因,所以零XML配置使得整个开发过程很放松,让工程师能够更好的将精力集中在编写实际的业务逻辑上。
Mybatis+Spring+SpringMVC的SSM架构使用mybatis generator工具来简化开发。
Mybatis+Springboot+SpringMVC的新架构就采用mybatis-spring-boot-starter。
spring+mybatis
我这里从最传统的spring+Mybatis项目开始讲起,因为要产生对比才能更好的理解新架构对开发的改变!
传统模式
在原先的项目中简单分析下mybatis与数据库在DAO层进行交互的一般流程:
第一步:首先先编写实体类,满足javaBean规范(有包,实现序列化接口,有无参数构造器,各个属性有相应的get/set方法),实体类对应数据库中的表,这里我用的是mysql数据库来做项目。
第二步:编写DAO接口,里面有一些对这个表所做的操作,具体的实现在mapper文件中写sql语句。
第三步:写mapper.xml映射文件,主要是映射实体类,和实现DAO接口的逻辑
并且在配置文件中要进行org.mybatis.spring.SqlSessionFactoryBean的配置,指定所有mapper文件所存在的包名
mapper文件的xml头格式也有要求:
<?xml version=”1.0” encoding=”UTF-8” ?>
<!DOCTYPE mapper PUBLIC “-//ibatis.apache.org//DTD Mapper 3.0//EN”
“http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
…
这是传统的模式与数据库进行交互,因为要编写大量的实体类entity,Dao接口,mapper文件,很难管理且开发太过恶心。
后来出现了mybatis generator工具来自动来自动生成这些东西,居然还有基于注解的去mapper化开发模式,这也是我今天总结的时候才发现的,这不是学jpa吗?
先来看看这个mybatis generator工具到底是啥玩意。。
mybatis generator工具模式 ##’
mybatis generator工具官网:http://mbg.cndocs.ml/
mybatis-generator 是一个代码自动生成工具,手动写入一个个实体类和mapper还有xml配置文件感觉会很麻烦,使用mybatis generator只需要简单的配置就能完成我们的工作,这里简述一下开发步骤。
MyBatis Generator (MBG) 是一个Mybatis的代码生成器 MyBatis 和 iBATIS. 他可以生成Mybatis各个版本的代码,和iBATIS 2.2.0版本以后的代码。 他可以内省数据库的表(或多个表)然后生成可以用来访问(多个)表的基础对象。 这样和数据库表进行交互时不需要创建对象和配置文件。 MBG的解决了对数据库操作有最大影响的一些简单的CRUD(插入,查询,更新,删除)操作。 您仍然需要对联合查询和存储过程手写SQL和对象。
mybatis generator的原理就是根据你数据库中已有的表自动生成对应的实体类,mapper以及DAO接口,我们先来操作一下(表已经事先在数据库中创建好了)
第一步:导入相关的jar包
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.annotation</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-osgi-bundle</artifactId>
<version>1.0.1-SP3</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.servlet</artifactId>
<version>3.0.1</version>
</dependency>
<!--测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- Mysql -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.7</version>
</dependency>
<!-- Mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--生成代码插件-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
第二步:新建生成代码的配置文件mybatis-generator-config.xml
具体更详细的各参数配置在这里:https://www.jianshu.com/p/e09d2370b796
注意这个文件是最坑的,一定不要设置错了,不然很尴尬。。。自动生成虽然好用,但是也要多做才能完全掌握其中奥义。
<generatorConfiguration>
<context id="prod">
<!-- RowBounds pagination -->
<plugin type="org.mybatis.generator.plugins.RowBoundsPlugin" />
<plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" />
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<commentGenerator>
<property name="suppressDate" value="true" />
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- jdbc连接 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql:///test"
userId="root"
password="294823013" />
<!-- 在javaModelGenerator标签下配置你需要生成的数据库实体的地址 -->
<javaModelGenerator targetPackage="com.mybatis.entity"
targetProject="src/main/java">
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 在sqlMapGenerator标签下配置mysql的xml配置文件 -->
<sqlMapGenerator targetPackage="mappers" targetProject="src/main/java" />
<!-- 在javaClientGenerator标签下配置mapper方法,相当于DAO接口,业务层调用里面的方法对数据库进行操作 -->
<javaClientGenerator targetPackage="com.mybatis.mapper"
targetProject="src/main/java" type="XMLMAPPER" />
<!-- 在table标签下配置数据库的表名和生成实体的表名,表名是koro_table,所生成的实体类是KoroTable -->
<table tableName="koro_table" domainObjectName="KoroTable">
</table>
</context>
</generatorConfiguration>
第三步:新建批处理类main方法
利用mybatis generator来进行自动生成,编写
public class App {
public static void main(String[] args) {
args = new String[] { "-configfile", "src\\main\\resources\\mybatis-generator-config.xml", "-overwrite" };
ShellRunner.main(args);
}
}
执行这个类就可以自动生成了,生成后的目录结构是这样的:
我们会发现我们生成了两个实体对象,一个是数据库映射对象,一个是Example对象。Example对象就是为了方便我们执行sql操作的类,可以使用Example类进行数据库的条件查询。同时mybatis-generator还帮助我们生成了sql的CRUD等操作。
com.mybatis.mapper下的KoroTableMapper.java就是DAO接口,里面是一些crud操作
public interface KoroTableMapper {
int countByExample(KoroTableExample example);
int deleteByExample(KoroTableExample example);
int deleteByPrimaryKey(Integer id);
int insert(KoroTable record);
int insertSelective(KoroTable record);
List<KoroTable> selectByExampleWithRowbounds(KoroTableExample example, RowBounds rowBounds);
List<KoroTable> selectByExample(KoroTableExample example);
KoroTable selectByPrimaryKey(Integer id);
int updateByExampleSelective(@Param("record") KoroTable record, @Param("example") KoroTableExample example);
int updateByExample(@Param("record") KoroTable record, @Param("example") KoroTableExample example);
int updateByPrimaryKeySelective(KoroTable record);
int updateByPrimaryKey(KoroTable record);
}
mappers目录下的是自动生成的mapper.xml文件,对应DAO接口的各个方法的实现
<mapper namespace="com.mybatis.mapper.KoroTableMapper" >
<resultMap id="BaseResultMap" type="com.mybatis.entity.KoroTable" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="NAME" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
</resultMap>
<sql id="Example_Where_Clause" >
<where >
<foreach collection="oredCriteria" item="criteria" separator="or" >
<if test="criteria.valid" >
<trim prefix="(" suffix=")" prefixOverrides="and" >
<foreach collection="criteria.criteria" item="criterion" >
<choose >
<when test="criterion.noValue" >
and ${criterion.condition}
</when>
<when test="criterion.singleValue" >
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue" >
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue" >
and ${criterion.condition}
<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >
`#{listItem}`
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause" >
<where >
<foreach collection="example.oredCriteria" item="criteria" separator="or" >
<if test="criteria.valid" >
<trim prefix="(" suffix=")" prefixOverrides="and" >
<foreach collection="criteria.criteria" item="criterion" >
<choose >
<when test="criterion.noValue" >
and ${criterion.condition}
</when>
<when test="criterion.singleValue" >
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue" >
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue" >
and ${criterion.condition}
<foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," >
`#{listItem}`
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List" >
id, NAME, age
</sql>
<select id="selectByExample" resultMap="BaseResultMap" parameterType="com.mybatis.entity.KoroTableExample" >
select
<if test="distinct" >
distinct
</if>
<include refid="Base_Column_List" />
from koro_table
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null" >
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from koro_table
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from koro_table
where id = #{id,jdbcType=INTEGER}
</delete>
<delete id="deleteByExample" parameterType="com.mybatis.entity.KoroTableExample" >
delete from koro_table
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="com.mybatis.entity.KoroTable" >
insert into koro_table (id, NAME, age
)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}
)
</insert>
<insert id="insertSelective" parameterType="com.mybatis.entity.KoroTable" >
insert into koro_table
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null" >
id,
</if>
<if test="name != null" >
NAME,
</if>
<if test="age != null" >
age,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null" >
`#{id,jdbcType=INTEGER},`
</if>
<if test="name != null" >
`#{name,jdbcType=VARCHAR},`
</if>
<if test="age != null" >
`#{age,jdbcType=INTEGER},`
</if>
</trim>
</insert>
<select id="countByExample" parameterType="com.mybatis.entity.KoroTableExample" resultType="java.lang.Integer" >
select count(*) from koro_table
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map" >
update koro_table
<set >
<if test="record.id != null" >
id = #{record.id,jdbcType=INTEGER},
</if>
<if test="record.name != null" >
NAME = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.age != null" >
age = #{record.age,jdbcType=INTEGER},
</if>
</set>
<if test="_parameter != null" >
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map" >
update koro_table
set id = #{record.id,jdbcType=INTEGER},
NAME = #{record.name,jdbcType=VARCHAR},
age = #{record.age,jdbcType=INTEGER}
<if test="_parameter != null" >
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="com.mybatis.entity.KoroTable" >
update koro_table
<set >
<if test="name != null" >
NAME = #{name,jdbcType=VARCHAR},
</if>
<if test="age != null" >
age = #{age,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.mybatis.entity.KoroTable" >
update koro_table
set NAME = #{name,jdbcType=VARCHAR},
age = #{age,jdbcType=INTEGER}
where id = #{id,jdbcType=INTEGER}
</update>
<select resultMap="BaseResultMap" parameterType="com.mybatis.entity.KoroTableExample" id="selectByExampleWithRowbounds" >
select
<if test="distinct" >
distinct
</if>
<include refid="Base_Column_List" />
from koro_table
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null" >
order by ${orderByClause}
</if>
</select>
</mapper>
springboot与mybatis整合
第一步:springboot与mybatis整合的导包:mysql连接与mybatis-spring-boot-starter即可
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
第二步:在application.properties文件中配置mybatis的相关项
#mybatis.config-location=classpath:mybatis-config.xml
#mybatis mapper文件的位置
mybatis.mapper-locations=classpath:mapper/.xml
#扫描pojo类的位置,在此处指明扫描实体类的包,在mapper中就可以不用写pojo类的全路径名了
mybatis.type-aliases-package=com.domain
jdbc.type=mysql
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=294823013
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
第三步:在数据库中建立表meaage并给些数据(准备好数据库)
第四步:编写实体类Message,名称与表名对应
public class Message {
private int id;
private String content;
private String name;
//省略get/set方法
//添加无参构造器
}
第五步:编写Dao接口
//加上该注解才能使用@MapperScan扫描到
@Mapper
public interface MessageDao {
Message findById(@Param("id")int id);
}
第六步:编写Dao对应的mapper文件
<mapper namespace="com.mybatis.domain.MessageDao">
<select id="findById" parameterType="int"
resultType="com.mybatis.domain.Message">
SELECT * FROM message WHERE id=#{id}
</select>
</mapper>
第七步:启动类
@SpringBootApplication
@MapperScan("mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
添加@MapperScan(“mapper”),以扫描mapper文件夹下的那些mapper文件
第八步:添加Controller类来简单测试
@RestController
public class MessageController {
@Autowired
private MessageDao messageDao;
@RequestMapping("/msg")
public Message msg(){
Message msg=messageDao.findById(1);
System.out.println(msg);
return msg;
}
}
第九步:测试,浏览器输入:http://localhost:8088/msg
得到结果:{“id”:1,”content”:”aaaaaaaaaa”,”name”:”o1”}
测试成功!!
springboot+mybatis的操作就是这些。。。(总之我觉得改变的话就是springboot将一对的xml配置信息全部简化放在application.properties中去进行配置,我们只需要去完成逻辑即可)
当我们需要一个很简单的DML功能时,如果去创建mapper文件并编写一堆语句的时候也许会显得很麻烦,这个时候就可以通过注解的方式简化配置,新建一个UserAnnotationDao通过注解的方式来实现增删改查:
接下来介绍不需要mapper文件来对应Dao接口的方法(其实本质就是用java配置取代xml配置的意思)
新建MessageAnnotationDao,但是这次不用mapper文件来实现Dao中的方法,用@Select和@Results注解来配置
在使用简单的DML操作时,为了不用mapper那么麻烦,我们可以采用注解方式直接配置。
控制层直接调用即可。
@Mapper
public interface MessageAnnotationDao {
@Select("SELECT * FROM message where id=#{id}")
@Results({
@Result(property="id",column="id"),
@Result(property="content",column="content"),
@Result(property="name",column="name")
})
public Message findById(int id);
}
使用注解自后就不需要mapper文件了,分别测试这几个方法均能正确执行,使用注解和使用xml的方式都差不多,通常情况下,如果没有复杂的连接查询,我们可以使用注解的方式,当设计到复杂的sql还是使用xml的方式更好掌控一些,所以通常情况下两种方式都会使用,根据sql的复杂程度选择不同的方式来提高开发效率。
关于不用mapper文件配置sql语句的注解有哪些?
1.传参方式
下面通过几种不同传参方式来实现前文中实现的插入操作。
-使用@Param
这个注解在控制层也会用到,用于声明html文件中form表单提交时的key与传参的参数名对应,这样就可以更加保险的传递参数。
Insert(“INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})”)
int insert(@Param(“name”) String name, @Param(“age”) Integer age);
这种方式很好理解,@Param中定义的name对应了SQL中的#{name},age对应了SQL中的#{age}。
-使用Map
如下代码,通过Map对象来作为传递参数的容器:
@Insert(“INSERT INTO USER(NAME, AGE) VALUES(#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})”)
int insertByMap(Map<String, Object> map);
对于Insert语句中需要的参数,我们只需要在map中填入同名的内容即可,具体如下面代码所示:
Map<String, Object> map = new HashMap<>();
map.put(“name”, “CCC”);
map.put(“age”, 40);
userMapper.insertByMap(map);
系统会自动识别,从map中找相同的key
-使用对象
除了Map对象,我们也可直接使用普通的Java对象来作为查询条件的传参,比如我们可以直接使用User对象:
@Insert(“INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})”)
int insertByUser(User user);
这样语句中的#{name}、#{age}就分别对应了User对象中的name和age属性。
2.增删改查(CRUD)
MyBatis针对不同的数据库操作分别提供了不同的注解来进行配置,在之前的示例中演示了@Insert,下面针对User表做一组最基本的增删改查作为示例:
public interface UserMapper {
@Select("SELECT * FROM user WHERE name = #{name}")
User findByName(@Param("name") String name);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);
@Update("UPDATE user SET age=#{age} WHERE name=#{name}")
void update(User user);
@Delete("DELETE FROM user WHERE id =#{id}")
void delete(Long id);
}
在完成了一套增删改查后,不妨我们试试下面的单元测试来验证上面操作的正确性:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
public class ApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
@Rollback
public void testUserMapper() throws Exception {
// insert一条数据,并select出来验证
userMapper.insert("AAA", 20);
User u = userMapper.findByName("AAA");
Assert.assertEquals(20, u.getAge().intValue());
// update一条数据,并select出来验证
u.setAge(30);
userMapper.update(u);
u = userMapper.findByName("AAA");
Assert.assertEquals(30, u.getAge().intValue());
// 删除这条数据,并select验证
userMapper.delete(u.getId());
u = userMapper.findByName("AAA");
Assert.assertEquals(null, u);
}
}
3.返回结果的绑定
对于增、删、改操作相对变化较小。而对于“查”操作,我们往往需要进行多表关联,汇总计算等操作,那么对于查询的结果往往就不再是简单的实体对象了,往往需要返回一个与数据库实体不同的包装类,那么对于这类情况,就可以通过@Results和@Result注解来进行绑定,具体如下:
@Results({
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age")
})
@Select("SELECT name, age FROM user")
List<User> findAll();
在上面代码中,@Result中的property属性对应User对象中的成员名,column对应SELECT出的字段名。在该配置中故意没有查出id属性,只对User对应中的name和age对象做了映射配置,这样可以通过下面的单元测试来验证查出的id为null,而其他属性不为null:
@Test
@Rollback
public void testUserMapper() throws Exception {
List<User> userList = userMapper.findAll();
for(User user : userList) {
Assert.assertEquals(null, user.getId());
Assert.assertNotEquals(null, user.getName());
}
}
具体的更多注解配置在mybatis开发文档中:http://www.mybatis.org/mybatis-3/zh/java-api.html
springboot+mybatis结合mybatis-generator工具
为了能最大程度的简化开发,我们如果在项目中使用springboot+mybatis的组合,那么在生成对应的文件上可以采用mybatis-generator工具。
在前言中说到,mybatis也发现了我们需要重复的去创建pojo类、mapper文件以及dao类并且需要配置它们之间的依赖关系可能会很麻烦,所以mybtis提供了一个mybatis generator工具来帮我们自动创建pojo类、mapper文件以及dao类并且会帮我们配置好它们的依赖关系,而我们只需要关系我们的业务逻辑直接使用就行了。
要使用mybatis generator工具需要在pom.xml文件中添加一个generator的maven工具:
接下来就以一个项目来讲,这个generatorConfig的xml文件是最容易出错的,但是只要自己独立完成了以后就可以完美掌握了,挽歌互勉。。。
参考文章:https://blog.csdn.net/pucao_cug/article/details/64499355 (这篇是配置maven generator插件的,很有借鉴意义)
https://blog.csdn.net/w410589502/article/details/70756764
第一步:我还是先把自己的POM包给你们看下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<groupId>myself.my</groupId>
<artifactId>spring-annotation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<tomcat.version>7.0.69</tomcat.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- springBoot的web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<!-- plugin配置用于指定使用插件 -->
<plugins>
<!-- 这个plugin里面又使用dependencies引入了mysql 的驱动和mybatis的相关jar包,
这个不能省略。 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>Generate MyBatis Files</id>
<goals>
<goal>generate</goal>
</goals>
<phase>generate</phase>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
</plugin>
<!-- 资源文件拷贝插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- spring-boot-maven-plugin插件 在SpringBoot项目中开启的方式有两种
一种是run java.application 还有一种就是这个插件开启-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 用于在子Pom中使用,继承中使用 -->
<pluginManagement>
<plugins>
<!-- Tomcat配置 用于远程部署java web项目-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
首先注意的:
这里用到spring-boot-starter基础和spring-boot-starter-test用来做单元测试验证数据访问
引入连接mysql的必要依赖mysql-connector-java
引入整合MyBatis的核心依赖mybatis-spring-boot-starter
这里不引入spring-boot-starter-jdbc依赖,是由于mybatis-spring-boot-starter中已经包含了此依赖
这是application.properties文件中的配置参数
`#Mybatis Generator configuration`
`#dao类和实体类的位置`
project =src/main/java
`#mapper文件的位置`
resources=src/main/java
`#根据数据库中的表生成对应的pojo类、dao、mapper`
jdbc_driver =com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql:///test
jdbc_user=root
jdbc_password=294823013
注意这个配置文件,跟之前的generator配置是一样的,格式千万注意,project是注明实体类生成的位置,resource是注明mapper文件生成的位置。
最容易出错的地方就在于配置这个generator的文件时,数据的格式不要写错!!!
<!-- 配置生成器 -->
<generatorConfiguration>
<!--执行generator插件生成文件的命令: call mvn mybatis-generator:generate -e -->
<!-- 引入配置文件 -->
<properties resource="application.properties"/>
<!--classPathEntry:数据库的JDBC驱动,换成你自己的驱动位置 可选 -->
<!-- 一个数据库一个context -->
<!--defaultModelType="flat" 大数据字段,不分表 -->
<context id="MysqlTables" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<!-- 自动识别数据库关键字,默认false,如果设置为true,根据SqlReservedWords中定义的关键字列表;
一般保留默认值,遇到数据库关键字(Java关键字),使用columnOverride覆盖 -->
<property name="autoDelimitKeywords" value="true" />
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="utf-8" />
<!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; -->
<property name="beginningDelimiter" value="`" />
<property name="endingDelimiter" value="`" />
<!-- 格式化java代码 -->
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
<!-- 格式化XML代码 -->
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<!-- 注释 -->
<commentGenerator >
<property name="suppressAllComments" value="false"/><!-- 是否取消注释 -->
<property name="suppressDate" value="true" /> <!-- 是否生成注释代时间戳-->
</commentGenerator>
<!-- jdbc连接参数,用application.properties文件的参数,SPEL表达式取值即可
因为这用到了mybatis generator技术来将数据库中的表自动生成mapper文件和实体类,所以直接用参数
配置数据库连接就不起作用了,必须要在这里手动配置 -->
<jdbcConnection driverClass="${jdbc_driver}" connectionURL="${jdbc_url}" userId="${jdbc_user}" password="${jdbc_password}" />
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 最主要的4个generator配置,这很容易写错 -->
<!-- 生成实体类地址 -->
<javaModelGenerator targetPackage="com.mybatis.domain" targetProject="${project}" >
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="mapper" targetProject="${resources}" >
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator targetPackage="com.mybatis.domain" targetProject="${project}" type="XMLMAPPER" >
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- table可以有多个,每个数据库中的表都可以写一个table,tableName表示要匹配的数据库表,也可以在tableName属性中通过使用%通配符来匹配所有数据库表,只有匹配的表才会自动生成文件 -->
<table tableName="user" enableCountByExample="true" enableUpdateByExample="true" enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true">
<property name="useActualColumnNames" value="false" />
<!-- 数据库表主键 -->
<generatedKey column="id" sqlStatement="Mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
这些都配置完后,我们要用插件启动测试能否自动生成
如何使用插件呢?
我们配置好POM中的插件后,在项目上右键–》run as–》run configrations
在点击Run Configurations以后,会弹出对话框,在对话框上找到Maven Build,然后右键并且点击new,如下图:
在新出现的界面上填写Name,Base directory,Goals这三个地方,其中Name可以随便写,Base directory是你的工程的路径,例如我的是E:\eclipse_workspace_2015\springmybatis,Goals这个地方不用变,照着图写,这个是maven插件的命令。至于Maven Runtime下拉框可以不选,也可以选择自己安装在eclipse外面的那个。
执行mybatis-generator:generate命令
点击Apply,在点击 Run,稍等一会,你可以看到generator执行成功了,如图:
生成文件:
注意配置不要错了即可,这就是spring或者springboot环境下与mybatis的整合。。。
使用数据库版本控制器
创建表的过程我们在实际开发系统的时候会经常使用,但是一直有一个问题存在,由于一个系统的程序版本通过git得到了很好的版本控制,而数据库结构并没有,即使我们通过Git进行了语句的版本化,那么在各个环境的数据库中如何做好版本管理呢?下面我们就通过本文来学习一下在Spring Boot中如何使用Flyway来管理数据库的版本。
Flyway简介
Flyway是一个简单开源数据库版本控制器(约定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客户端等,还提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。
Flyway是一款开源的数据库版本管理工具,它更倾向于规约优于配置的方式。Flyway可以独立于应用实现管理并跟踪数据库变更,支持数据库版本自动升级,并且有一套默认的规约,不需要复杂的配置,Migrations可以写成SQL脚本,也可以写在Java代码中,不仅支持Command Line和Java API,还支持Build构建工具和Spring Boot等,同时在分布式环境下能够安全可靠地升级数据库,同时也支持失败恢复等。
避免不正当的操作损坏数据库的结构导致严重事故,目前支持的数据库主要有:Oracle, SQL Server, SQL Azure, DB2, DB2 z/OS, MySQL(including Amazon RDS), MariaDB, Google Cloud SQL, PostgreSQL(including Amazon RDS and Heroku), Redshift, Vertica, H2, Hsql, Derby, SQLite, SAP HANA, solidDB, Sybase ASE and Phoenix.
为什么使用Flyway?
通常在项目开始时会针对数据库进行全局设计,但在开发产品新特性过程中,难免会遇到需要更新数据库Schema的情况,比如:添加新表,添加新字段和约束等,这种情况在实际项目中也经常发生。那么,当开发人员完成了对数据库更的SQL脚本后,如何快速地在其他开发者机器上同步?并且如何在测试服务器上快速同步?以及如何保证集成测试能够顺利执行并通过呢?
假设以Spring Boot技术栈项目为例,可能有人会说,本地使用Hibernate自动更新数据库Schema模式,然后让QA或DEV到测试服务器上手动执行SQL脚本,同时可以写一个Gradle任务自动执行更新。
个人觉得,对于Hibernate自动更新数据库,感觉不靠谱,不透明,控制自由度不高,而且有时很容易就会犯错,比如:用SQL创建的某个字段为VARCHAR类型,而在Entity中配置的为CHAR类型,那么在运行集成测试时,自动创建的数据库表中的字段为CHAR类型,而实际SQL脚本期望的是VARCHAR类型,虽然测试通过了,但不是期望的行为,并且在本地bootRun或服务器上运行Service时都会失败。另外,到各测试服务器上手动执行SQL脚本费时费神费力的,干嘛不自动化呢,当然,对于高级别和PROD环境,还是需要DBA手动执行的。最后,写一段自动化程序来自动执行更新,想法是很好的,那如果已经有了一些插件或库可以帮助你更好地实现这样的功能,为何不好好利用一下呢,当然,如果是为了学习目的,重复造轮子是无可厚非的。
其实,以上问题可以通过Flyway工具来解决,Flyway可以实现自动化的数据库版本管理,并且能够记录数据库版本更新记录,Flyway官网对Why database migrations结合示例进行了详细的阐述,有兴趣可以参阅一下。
https://flywaydb.org/ (官方网站)
第一步:首先先加入依赖
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.0.3</version>
</dependency>