Springboot+MyBatis+JPA集成
1.前言
springboot最近可谓是非常的火,本人也在项目中尝到了甜头。之前一直使用springboot+jpa,用了一段时间发现jpa不是太灵活,也有可能是我不精通jpa,总之为了多学学springboot我决定尝试一下springboot+mybatis+jpa三项集成,集成过程中遇到了很多问题,但最后总算是集成成功了,现在记录一下方法。
1.1 如何使用mybatis generator自动生成xxxmapper.java接口以及xxxmapper.xml文件
以前用过springmvc,知道写xxxmapper.java接口以及xxxmapper.xml文件的辛苦,这次集成最先想到的就是先解决如何使用如何使用mybatis generator自动生成这些文件的问题。
先扔出mybatis generator的官网->请戳这里
我使用的maven集成插件的方式,ide使用的是idea
1.1.1 创建项目
1.1.2 修改pom.xml
添加了druid依赖和mybatis generator插件
其他依赖请自行添加
<?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>com.study.springboot</groupid> <artifactid>mybatis</artifactid> <version>1.0</version> <packaging>war</packaging> <name>demo</name> <description>springboot+mybatis+jpa</description> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.9.release</version> <relativepath/> </parent> <properties> <project.build.sourceencoding>utf-8</project.build.sourceencoding> <project.reporting.outputencoding>utf-8</project.reporting.outputencoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-jpa</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-web</artifactid> </dependency> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <scope>runtime</scope> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-tomcat</artifactid> <!--<scope>provided</scope>--> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <!-- 阿里巴巴连接池druid --> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid</artifactid> <version>1.1.5</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> <!-- mybatis generator 插件 --> <plugin> <groupid>org.mybatis.generator</groupid> <artifactid>mybatis-generator-maven-plugin</artifactid> <version>1.3.5</version> <executions> <execution> <id>generate mybatis artifacts</id> <goals> <goal>generate</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
1.1.3 配置generatorconfiguration
generatorconfig.xml放在resource文件夹下
常用配置已经注释了,请自行查看
<?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> <!-- 可以用于加载配置项或者配置文件,在整个配置文件中就可以使用${propertykey}的方式来引用配置项 resource:配置资源加载地址,使用resource,mbg从classpath开始找,比如com/myproject/generatorconfig.properties url:配置资源加载地址,使用url的方式,比如file:///c:/myfolder/generatorconfig.properties 注意,两个属性只能选址一个 另外,如果使用了mybatis-generator-maven-plugin,那么在pom.xml中定义的properties都可以直接在generatorconfig.xml中使用 <properties resource="" url="" /> --> <!--<properties resource="db.properties"/>--> <!-- 在mbg工作的时候,需要额外加载的依赖包 location属性指明加载jar/zip包的全路径 --> <classpathentry location="c:\users\semi\.m2\repository\mysql\mysql-connector-java\5.1.38\mysql-connector-java-5.1.38.jar"/> <!-- context:生成一组对象的环境 id:必选,上下文id,用于在生成错误时提示 defaultmodeltype:指定生成对象的样式 1. conditional:类似hierarchical 2. flat:所有内容(主键,blob)等全部生成在一个对象中 3. hierarchical:主键生成一个xxkey对象(key class),blob等单独生成一个对象,其他简单属性在一个对象中(record class) targetruntime: 1. mybatis3:默认的值,生成基于mybatis3.x以上版本的内容,包括xxxbysample 2. mybatis3simple:类似mybatis3,只是不生成xxxbysample introspectedcolumnimpl:类全限定名,用于扩展mbg --> <context id="mybatis" targetruntime="mybatis3"> <!-- 自动识别数据库关键字,默认false,如果设置为true,根据sqlreservedwords中定义的关键字列表 一般保留默认值,遇到数据库关键字(java关键字),使用columnoverride覆盖 --> <property name="autodelimitkeywords" value="false"/> <!-- 生成的java文件的编码 --> <property name="javafileencoding" value="utf-8"/> <!-- 格式化java代码 --> <property name="javaformatter" value="org.mybatis.generator.api.dom.defaultjavaformatter"/> <!-- 格式化xml代码 --> <property name="xmlformatter" value="org.mybatis.generator.api.dom.defaultxmlformatter"/> <!-- 不生成注释 --> <commentgenerator> <property name="suppressallcomments" value="true"/> <property name="suppressdate" value="true"/> </commentgenerator> <!-- jdbc连接配置 --> <jdbcconnection driverclass="com.mysql.jdbc.driver" connectionurl="jdbc:mysql://localhost:3306/test" userid="root" password="123456"/> <!-- java类型处理器 用于处理db中的类型到java中的类型,默认使用javatyperesolverdefaultimpl 注意一点,默认会先尝试使用integer,long,short等来对应decimal和numeric数据类型 --> <javatyperesolver> <!-- true:使用bigdecimal对应decimal和 numeric数据类型 false:默认 scale>0;length>18:使用bigdecimal scale=0;length[10,18]:使用long scale=0;length[5,9]:使用integer scale=0;length<5:使用short --> <property name="forcebigdecimals" value="false"/> </javatyperesolver> <!-- java模型创建器,是必须要的元素 负责: 1. key类(见context的defaultmodeltype) 2. java类 3. 查询类 targetpackage:生成的类要放的包,真实的包受enablesubpackages属性控制 targetproject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中,如果目录不存在,mbg不会自动建目录 --> <javamodelgenerator targetpackage="com.study.springboot.mybatis.model" targetproject="e:\workspace\study\springboot\mybatis\src\main\java"> <!-- 自动为每一个生成的类创建一个构造方法,构造方法包含了所有的field,而不是使用setter --> <!--<property name="constructorbased" value="false"/>--> <!-- 在targetpackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false --> <property name="enablesubpackages" value="false"/> <!-- 是否创建一个不可变的类,如果为true 那么mbg会创建一个没有setter方法的类,取而代之的是类似constructorbased的类 --> <!--<property name="immutable" value="false"/>--> <!-- 设置一个根对象 如果设置了这个根对象,那么生成的keyclass或者recordclass会继承这个类,在table的rootclass属性中可以覆盖该选项 注意: 如果在key class或者record class中有root class相同的属性,mbg就不会重新生成这些属性了,包括: 1. 属性名相同,类型相同,有相同的getter/setter方法 --> <!--<property name="rootclass" value="com._520it.mybatis.domain.basedomain"/>--> <!-- 设置是否在getter方法中,对string类型字段调用trim()方法 --> <property name="trimstrings" value="true"/> </javamodelgenerator> <!-- 生成sql map的xml文件生成器 注意,在mybatis3之后,我们可以使用mapper.xml文件+mapper接口(或者不用mapper接口) 或者只使用mapper接口+annotation,所以,如果javaclientgenerator配置中配置了需要生成xml的话,这个元素就必须配置 targetpackage/targetproject:同javamodelgenerator --> <sqlmapgenerator targetpackage="mapper" targetproject="e:\workspace\study\springboot\mybatis\src\main\resources"> <!-- 在targetpackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false --> <property name="enablesubpackages" value="false"/> </sqlmapgenerator> <!-- 对于mybatis来说,即生成mapper接口 注意,如果没有配置该元素,那么默认不会生成mapper接口 targetpackage/targetproject:同javamodelgenerator type:选择怎么生成mapper接口(在mybatis3/mybatis3simple下) 1. annotatedmapper:会生成使用mapper接口+annotation的方式创建(sql生成在annotation中)不会生成对应的xml 2. mixedmapper:使用混合配置,会生成mapper接口,并适当添加合适的annotation,但是xml会生成在xml中 3. xmlmapper:会生成mapper接口,接口完全依赖xml 注意,如果context是mybatis3simple:只支持annotatedmapper和xmlmapper --> <javaclientgenerator type="xmlmapper" targetpackage="com.study.springboot.mybatis.mapper" targetproject="e:\workspace\study\springboot\mybatis\src\main\java"> <!-- 在targetpackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false --> <property name="enablesubpackages" value="false"/> <!-- 可以为所有生成的接口添加一个父接口,但是mbg只负责生成,不负责检查 <property name="rootinterface" value=""/> --> </javaclientgenerator> <!-- 选择一个table来生成相关文件,可以有一个或多个table,必须要有table元素 选择的table会生成一下文件: 1. sql map文件 2. 生成一个主键类 3. 除了blob和主键的其他字段的类 4. 包含blob的类 5. 一个用户生成动态查询的条件类(selectbyexample, deletebyexample)可选 6. mapper接口(可选) tablename(必要):要生成对象的表名,%表示通配,即为该数据库下的所有表生成xml文件 注意:大小写敏感问题.正常情况下,mbg会自动的去识别数据库标识符的大小写敏感度,在一般情况下 mbg会根据设置的schema,catalog或tablename去查询数据表,按照下面的流程: 1. 如果schema,catalog或tablename中有空格,那么设置的是什么格式,就精确的使用指定的大小写格式去查询 2. 否则,如果数据库的标识符使用大写的,那么mbg自动把表名变成大写再查找 3. 否则,如果数据库的标识符使用小写的,那么mbg自动把表名变成小写再查找 4. 否则,使用指定的大小写格式查询 另外,如果在创建表的时候,使用的""把数据库对象规定大小写,就算数据库标识符是使用的大写,在这种情况下也会使用给定的大小写来创建表名 这个时候,请设置delimitidentifiers="true"即可保留大小写格式 可选: 1. schema:数据库的schema 2. catalog:数据库的catalog 3. alias:为数据表设置的别名,如果设置了alias,那么生成的所有的select sql语句中,列名会变成:alias_actualcolumnname 4. domainobjectname:生成的domain类的名字,如果不设置,直接使用表名作为domain类的名字;可以设置为somepck.domainname,那么会自动把domainname类再放到somepck包里面 5. enableinsert(默认true):指定是否生成insert语句 6. enableselectbyprimarykey(默认true):指定是否生成按照主键查询对象的语句(就是getbyid或get) 7. enableselectbyexample(默认true):mybatis3simple为false,指定是否生成动态查询语句 8. enableupdatebyprimarykey(默认true):指定是否生成按照主键修改对象的语句(即update) 9. enabledeletebyprimarykey(默认true):指定是否生成按照主键删除对象的语句(即delete) 10. enabledeletebyexample(默认true):mybatis3simple为false,指定是否生成动态删除语句 11. enablecountbyexample(默认true):mybatis3simple为false,指定是否生成动态查询总条数语句(用于分页的总条数查询) 12. enableupdatebyexample(默认true)mybatis3simple为false,指定是否生成动态修改语句(只修改对象中不为空的属性) 13. modeltype:参考context元素的defaultmodeltype,相当于覆盖 14. delimitidentifiers:参考tablename的解释,注意,默认的delimitidentifiers是双引号,如果类似mysql这样的数据库,使用的是`(反引号,那么还需要设置context的beginningdelimiter和endingdelimiter属性) 15. delimitallcolumns:设置是否所有生成的sql中的列名都使用标识符引起来.默认为false,delimitidentifiers参考context的属性 注意,table里面很多参数都是对javamodelgenerator,context等元素的默认属性的一个复写 --> <table tablename="%" enablecountbyexample="false" enableupdatebyexample="false" enabledeletebyexample="false" enableselectbyexample="false" selectbyexamplequeryid="false"> <!-- 参考javamodelgenerator的constructorbased属性 --> <!--<property name="constructorbased" value="false"/>--> <!-- 默认为false,如果设置为true,在生成的sql中,table名字不会加上catalog或schema --> <!--<property name="ignorequalifiersatruntime" value="false"/>--> <!-- 参考javamodelgenerator的immutable属性 --> <!--<property name="immutable" value="false"/>--> <!-- 指定是否只生成domain类,如果设置为true,只生成domain类,如果还配置了sqlmapgenerator,那么在mapper xml文件中,只生成resultmap元素 --> <!--<property name="modelonly" value="false"/>--> <!-- 参考javamodelgenerator的rootclass属性 --> <!--<property name="rootclass" value=""/>--> <!-- 参考javaclientgenerator的rootinterface属性 --> <!--<property name="rootinterface" value=""/>--> <!-- 如果设置了runtimecatalog,那么在生成的sql中,使用该指定的catalog,而不是table元素上的catalog --> <!--<property name="runtimecatalog" value=""/>--> <!-- 如果设置了runtimeschema,那么在生成的sql中,使用该指定的schema,而不是table元素上的schema --> <!--<property name="runtimeschema" value=""/>--> <!-- 如果设置了runtimetablename,那么在生成的sql中,使用该指定的tablename,而不是table元素上的tablename --> <!--<property name="runtimetablename" value=""/>--> <!-- 注意,该属性只针对mybatis3simple有用 如果选择的runtime是mybatis3simple,那么会生成一个selectall方法,如果指定了selectallorderbyclause,那么会在该sql中添加指定的这个order条件 --> <!--<property name="selectallorderbyclause" value="age desc,username asc"/>--> <!-- 如果设置为true,生成的model类会直接使用column本身的名字,而不会再使用驼峰命名方法,比如born_date,生成的属性名字就是born_date,而不会是borndate --> <!--<property name="useactualcolumnnames" value="false"/>--> <!-- generatedkey用于生成生成主键的方法 如果设置了该元素,mbg会在生成的<insert>元素中生成一条正确的<selectkey>元素,该元素可选 column:主键的列名 sqlstatement:要生成的selectkey语句,有以下可选项: cloudscape:相当于selectkey的sql为:values identity_val_local() db2 :相当于selectkey的sql为:values identity_val_local() db2_mf :相当于selectkey的sql为:select identity_val_local() from sysibm.sysdummy1 derby :相当于selectkey的sql为:values identity_val_local() hsqldb :相当于selectkey的sql为:call identity() informix :相当于selectkey的sql为:select dbinfo('sqlca.sqlerrd1') from systables where tabid=1 mysql :相当于selectkey的sql为:select last_insert_id() sqlserver :相当于selectkey的sql为:select scope_identity() sybase :相当于selectkey的sql为:select @@identity jdbc :相当于在生成的insert元素上添加usegeneratedkeys="true"和keyproperty属性 --> <!--<generatedkey column="" sqlstatement=""/>--> <!-- 该元素会在根据表中列名计算对象属性名之前先重命名列名,非常适合用于表中的列都有公用的前缀字符串的时候 比如列名为:cust_id,cust_name,cust_email,cust_address等 那么就可以设置searchstring为"^cust_",并使用空白替换,那么生成的customer对象中的属性名称就不是 custid,custname等,而是先被替换为id,name,email,然后变成属性:id,name,email 注意,mbg是使用java.util.regex.matcher.replaceall来替换searchstring和replacestring的 如果使用了columnoverride元素,该属性无效 --> <!--<columnrenamingrule searchstring="" replacestring=""/>--> <!-- 用来修改表中某个列的属性,mbg会使用修改后的列来生成domain的属性 column:要重新设置的列名 注意,一个table元素中可以有多个columnoverride元素 --> <!--<columnoverride column="username">--> <!-- 使用property属性来指定列要生成的属性名称 --> <!--<property name="property" value="username"/>--> <!-- javatype用于指定生成的domain的属性类型,使用类型的全限定名 --> <!--<property name="javatype" value=""/>--> <!-- jdbctype用于指定该列的jdbc类型 --> <!--<property name="jdbctype" value=""/>--> <!-- typehandler:用于指定该列使用到的typehandler,如果要指定,配置类型处理器的全限定名 注意,mybatis中,不会生成到mybatis-config.xml中的typehandler 只会生成类似:where id = #{id,jdbctype=bigint,typehandler=com._520it.mybatis.mytypehandler}的参数描述 --> <!--<property name="jdbctype" value=""/>--> <!-- 参考table元素的delimitallcolumns配置,默认为false --> <!--<property name="delimitedcolumnname" value=""/>--> <!-- ignorecolumn设置一个mgb忽略的列,如果设置了改列,那么在生成的domain中,生成的sql中,都不会有该列出现 column:指定要忽略的列的名字 delimitedcolumnname:参考table元素的delimitallcolumns配置,默认为false 注意,一个table元素中可以有多个ignorecolumn元素 --> <!--<ignorecolumn column="deptid" delimitedcolumnname=""/>--> </table> </context> </generatorconfiguration>
1.1.4 生成xxxmapper.java接口以及xxxmapper.xml文件
注意,如果存放xxxmapper.java和xxxmapper.xml文件的包不存在会报错
1.1.5 修改自动生成的实体类
对于model包下的实体类需要添加基于jpa的注解,否则jpa接口无法引用
例如对于user.java实体类需要进行如下修改
package com.study.springboot.mybatis.model; import javax.persistence.*; @entity @table(name = "user") public class user { @id @generatedvalue @column(name = "id") private integer id; @column(name = "user_name") private string username; @column(name = "passwd") private string passwd; @column(name = "nick_name") private string nickname; @column(name = "telephone") private string telephone; @column(name = "email") private string email; @column(name = "authority") private integer authority; @column(name = "department") private string department; @column(name = "create_at") private string createat; @column(name = "update_at") private string updateat; public integer getid() { return id; } public void setid(integer id) { this.id = id; } public string getusername() { return username; } public void setusername(string username) { this.username = username == null ? null : username.trim(); } public string getpasswd() { return passwd; } public void setpasswd(string passwd) { this.passwd = passwd == null ? null : passwd.trim(); } public string getnickname() { return nickname; } public void setnickname(string nickname) { this.nickname = nickname == null ? null : nickname.trim(); } public string gettelephone() { return telephone; } public void settelephone(string telephone) { this.telephone = telephone == null ? null : telephone.trim(); } public string getemail() { return email; } public void setemail(string email) { this.email = email == null ? null : email.trim(); } public integer getauthority() { return authority; } public void setauthority(integer authority) { this.authority = authority; } public string getdepartment() { return department; } public void setdepartment(string department) { this.department = department == null ? null : department.trim(); } public string getcreateat() { return createat; } public void setcreateat(string createat) { this.createat = createat == null ? null : createat.trim(); } public string getupdateat() { return updateat; } public void setupdateat(string updateat) { this.updateat = updateat == null ? null : updateat.trim(); } }
1.1.6 添加xxxjpa接口,例如userjpa.java
import org.springframework.data.jpa.repository.jparepository; import org.springframework.data.jpa.repository.jpaspecificationexecutor; import java.io.serializable; public interface userjpa extends serializable, jparepository<user, integer>, jpaspecificationexecutor<user> { }
1.1.7 测试
测试之前需要配置application.yml(你的有能是application.properties,改一下后缀名即可,我比较喜欢.yml文件的简洁)
spring: datasource: type: com.alibaba.druid.pool.druiddatasource url: jdbc:mysql://localhost:3306/test?useunicode=true&characterencoding=utf8&charactersetresults=utf8 driver-class-name: com.mysql.jdbc.driver username: root password: 123456 mybatis: # 重要配置 type-aliases-package: com.study.springboot.mybatis.model mapper-locations: classpath:mapper/*.xml
对于每一个xxxmapper.java接口,需要使用@component注解
自动生成的xxxmapper.java接口是不带@component注解的
@component public interface usermapper { int deletebyprimarykey(integer id); int insert(user record); int insertselective(user record); user selectbyprimarykey(integer id); int updatebyprimarykeyselective(user record); int updatebyprimarykey(user record); }
在入口类中需要添加@mapperscan("com.study.springboot.mybatis.mapper")注解
@springbootapplication @mapperscan("com.study.springboot.mybatis.mapper") public class mybatisapplication { public static void main(string[] args) { springapplication.run(mybatisapplication.class, args); } }
打开测试类,为测试类添加@mapperscan("com.study.springboot.mybatis.mapper")注解
@runwith(springrunner.class) @springboottest @mapperscan("com.study.springboot.mybatis.mapper") public class mybatisapplicationtests { @autowired private usermapper usermapper; @autowired private userjpa userjpa; @test public void contextloads() { system.out.println(usermapper.selectbyprimarykey(11).getusername()); system.out.println(userjpa.findone(11).getusername()); } }
最后如果出现
java.lang.noclassdeffounderror: org/apache/ibatis/session/sqlsession
的错误,请检查本地maven仓库的配置,有可能是没有maven没有下载需要引用的包
---恢复内容结束---
---恢复内容结束---
推荐阅读
-
SpringBoot集成JPA
-
迷你PS小程序-集成的开放式海报、油墨电子签名、图片拖拽可单独食用
-
在wamp集成环境下升级php版本(实现方法)_php技巧
-
Vue集成 富文本编辑器Ueditor读取相对路径资源显示不出的问题
-
asp.net core 2.0 webapi集成signalr(实例讲解)
-
使用docker创建集成服务lnmp环境
-
Tongue Twister-快速集成华为实时语音识别服务玩转绕口令
-
Spring集成jedis的配置与使用简单实例
-
SpringBoot集成shiro,MyRealm中无法@Autowired注入Service的问题
-
Spring-Boot 集成Solr客户端的详细步骤