Mybatis在spring和springboot框架中的操作总结

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);
    }
}

执行这个类就可以自动生成了,生成后的目录结构是这样的:
logo

我们会发现我们生成了两个实体对象,一个是数据库映射对象,一个是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>

标签中是对应数据库表的所有字段的映射等等,mybatis-generator为我们全自动化的根据数据库表结构生成实体类,DAO接口以及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
logo

在点击Run Configurations以后,会弹出对话框,在对话框上找到Maven Build,然后右键并且点击new,如下图:
logo

在新出现的界面上填写Name,Base directory,Goals这三个地方,其中Name可以随便写,Base directory是你的工程的路径,例如我的是E:\eclipse_workspace_2015\springmybatis,Goals这个地方不用变,照着图写,这个是maven插件的命令。至于Maven Runtime下拉框可以不选,也可以选择自己安装在eclipse外面的那个。
logo

执行mybatis-generator:generate命令

点击Apply,在点击 Run,稍等一会,你可以看到generator执行成功了,如图:
logo

生成文件:
logo

注意配置不要错了即可,这就是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>
坚持原创技术分享,您的支持将鼓励我继续创作!
+