這兩天啓動了一個新項目因爲項目組成員一直都使用的是mybatis,雖然個人比較喜歡jpa這種極簡的模式,但是爲了項目保持統一性技術選型還是定了 mybatis。到網上找了一下關於spring boot和mybatis組合的相關資料,各種各樣的形式都有,看的人心累,結合了mybatis的官方demo和文檔終於找到了最簡的兩種模式,花了一天時間總結後分享出來。
orm框架的本質是簡化編程中操作數據庫的編碼,發展到現在基本上就剩兩家了,一個是宣稱可以不用寫一句SQL的hibernate,一個是可以靈活調試動態sql的mybatis,兩者各有特點,在企業級系統開發中可以根據需求靈活使用。發現一個有趣的現象:傳統企業大都喜歡使用hibernate,互聯網行業通常使用mybatis。
hibernate特點就是所有的sql都用Java代碼來生成,不用跳出程序去寫(看)sql,有着編程的完整性,發展到最頂端就是spring data jpa這種模式了,基本上根據方法名就可以生成對應的sql了,有不太瞭解的可以看我的上篇文章springboot(五):spring data jpa的使用。
mybatis初期使用比較麻煩,需要各種配置文件、實體類、dao層映射關聯、還有一大推其它配置。當然mybatis也發現了這種弊端,初期開發了generator可以根據表結果自動生產實體類、配置文件和dao層代碼,可以減輕一部分開發量;後期也進行了大量的優化可以使用註解了,自動管理dao層和配置文件等,發展到最頂端就是今天要講的這種模式了,mybatis-spring-boot-starter就是springboot+mybatis可以完全註解不用配置文件,也可以簡單配置輕鬆上手。
現在想想spring boot 就是牛逼呀,任何東西只要關聯到spring boot都是化繁爲簡。
mybatis-spring-boot-starter
官方說明:MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot
其實就是myBatis看spring boot這麼火熱也開發出一套解決方案來湊湊熱鬧,但這一湊確實解決了很多問題,使用起來確實順暢了許多。mybatis-spring-boot-starter主要有兩種解決方案,一種是使用註解解決一切問題,一種是簡化後的老傳統。
當然任何模式都需要首先引入mybatis-spring-boot-starter的pom文件,現在最新版本是1.1.1(剛好快到雙11了 :)。
1
2
3
4
5
|
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version> 1.1 . 1 </version> </dependency> |
好了下來分別介紹兩種開發模式。
無配置文件註解版
就是一切使用註解搞定。
1 添加相關maven文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version> 1.1 . 1 </version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional> true </optional> </dependency> </dependencies> |
完整的pom包這裏就不貼了,大家直接看源碼。
2、application.properties 添加相關配置
1
2
3
4
5
6
|
mybatis.type-aliases- package =com.neo.entity spring.datasource.driverClassName
= com.mysql.jdbc.Driver spring.datasource.url
= jdbc:mysql: //localhost:3306/test1?useUnicode=true&characterEncoding=utf-8 spring.datasource.username
= root spring.datasource.password
= root |
springboot會自動加載spring.datasource.*相關配置,數據源就會自動注入到sqlSessionFactory中,sqlSessionFactory會自動注入到Mapper中,對了你一切都不用管了,直接拿起來使用就行了。
在啓動類中添加對mapper包掃描@MapperScan。
1
2
3
4
5
6
7
8
|
@SpringBootApplication @MapperScan ( "com.neo.mapper" ) public
class
Application { public
static
void
main(String[] args) { SpringApplication.run(Application. class ,
args); } } |
或者直接在Mapper類上面添加註解@Mapper,建議使用上面那種,不然每個mapper加個註解也挺麻煩的。
3、開發Mapper
第三步是最關鍵的一塊,sql生產都在這裏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
interface
UserMapper { @Select ( "SELECT
* FROM users" ) @Results ({ @Result (property
= "userSex" ,
column = "user_sex" ,
javaType = UserSexEnum. class ), @Result (property
= "nickName" ,
column = "nick_name" ) }) List<UserEntity>
getAll(); @Select ( "SELECT
* FROM users WHERE id = #{id}" ) @Results ({ @Result (property
= "userSex" ,
column = "user_sex" ,
javaType = UserSexEnum. class ), @Result (property
= "nickName" ,
column = "nick_name" ) }) UserEntity
getOne(Long id); @Insert ( "INSERT
INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})" ) void
insert(UserEntity user); @Update ( "UPDATE
users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}" ) void
update(UserEntity user); @Delete ( "DELETE
FROM users WHERE id =#{id}" ) void
delete(Long id); } |
爲了更接近生產我特地將user_sex、nick_name兩個屬性在數據庫加了下劃線和實體類屬性名不一致,另外user_sex使用了枚舉。
- @Select 是查詢類的註解,所有的查詢均使用這個
- @Result 修飾返回的結果集,關聯實體類屬性和數據庫字段一一對應,如果實體類屬性和數據庫屬性名保持一致,就不需要這個屬性來修飾。
- @Insert 插入數據庫使用,直接傳入實體類會自動解析屬性到對應的值
- @Update 負責修改,也可以直接傳入對象
- @delete 負責刪除
注意,使用#符號和$符號的不同:
1
2
3
4
5
6
7
|
//
This example creates a prepared statement, something like select * from teacher where name = ?; @Select ( "Select
* from teacher where name = #{name}" ) Teacher
selectTeachForGivenName( @Param ( "name" )
String name); //
This example creates n inlined statement, something like select * from teacher where name = 'someName'; @Select ( "Select
* from teacher where name = '${name}'" ) Teacher
selectTeachForGivenName( @Param ( "name" )
String name); |
4、使用
上面三步就基本完成了相關dao層開發,使用的時候當作普通的類注入進入就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@RunWith (SpringRunner. class ) @SpringBootTest public
class
UserMapperTest { @Autowired private
UserMapper UserMapper; @Test public
void
testInsert() throws
Exception { UserMapper.insert( new
UserEntity( "aa" ,
"a123456" ,
UserSexEnum.MAN)); UserMapper.insert( new
UserEntity( "bb" ,
"b123456" ,
UserSexEnum.WOMAN)); UserMapper.insert( new
UserEntity( "cc" ,
"b123456" ,
UserSexEnum.WOMAN)); Assert.assertEquals( 3 ,
UserMapper.getAll().size()); } @Test public
void
testQuery() throws
Exception { List<UserEntity>
users = UserMapper.getAll(); System.out.println(users.toString()); } @Test public
void
testUpdate() throws
Exception { UserEntity
user = UserMapper.getOne(3l); System.out.println(user.toString()); user.setNickName( "neo" ); UserMapper.update(user); Assert.assertTrue(( "neo" .equals(UserMapper.getOne(3l).getNickName()))); } } |
源碼中controler層有完整的增刪改查,這裏就不貼了。
極簡xml版本
極簡xml版本保持映射文件的老傳統,優化主要體現在不需要實現dao的是實現層,系統會自動根據方法名在映射文件中找對應的sql。
1、配置
pom文件和上個版本一樣,只是application.properties新增以下配置。
1
2
|
mybatis.config-locations=classpath:mybatis/mybatis-config.xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml |
指定了mybatis基礎配置文件和實體類映射文件的地址。
mybatis-config.xml 配置。
1
2
3
4
5
6
7
8
9
10
|
<configuration> <typeAliases> <typeAlias
alias= "Integer"
type= "java.lang.Integer"
/> <typeAlias
alias= "Long"
type= "java.lang.Long"
/> <typeAlias
alias= "HashMap"
type= "java.util.HashMap"
/> <typeAlias
alias= "LinkedHashMap"
type= "java.util.LinkedHashMap"
/> <typeAlias
alias= "ArrayList"
type= "java.util.ArrayList"
/> <typeAlias
alias= "LinkedList"
type= "java.util.LinkedList"
/> </typeAliases> </configuration> |
這裏也可以添加一些mybatis基礎的配置。
2、添加User的映射文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
<mapper
namespace= "com.neo.mapper.UserMapper"
> <resultMap
id= "BaseResultMap"
type= "com.neo.entity.UserEntity"
> <id
column= "id"
property= "id"
jdbcType= "BIGINT"
/> <result
column= "userName"
property= "userName"
jdbcType= "VARCHAR"
/> <result
column= "passWord"
property= "passWord"
jdbcType= "VARCHAR"
/> <result
column= "user_sex"
property= "userSex"
javaType= "com.neo.enums.UserSexEnum" /> <result
column= "nick_name"
property= "nickName"
jdbcType= "VARCHAR"
/> </resultMap> <sql
id= "Base_Column_List"
> id,
userName, passWord, user_sex, nick_name </sql> <select
id= "getAll"
resultMap= "BaseResultMap"
> SELECT
<include
refid= "Base_Column_List"
/> FROM
users </select> <select
id= "getOne"
parameterType= "java.lang.Long"
resultMap= "BaseResultMap"
> SELECT
<include
refid= "Base_Column_List"
/> FROM
users WHERE
id = #{id} </select> <insert
id= "insert"
parameterType= "com.neo.entity.UserEntity"
> INSERT
INTO users (userName,passWord,user_sex)
VALUES (#{userName},
#{passWord}, #{userSex}) </insert> <update
id= "update"
parameterType= "com.neo.entity.UserEntity"
> UPDATE
users
SET
< if
test= "userName
!= null" >userName
= #{userName},</ if > < if
test= "passWord
!= null" >passWord
= #{passWord},</ if > nick_name
= #{nickName} WHERE
id
= #{id} </update> <delete
id= "delete"
parameterType= "java.lang.Long"
> DELETE
FROM users
WHERE
id
=#{id} </delete> </mapper> |
其實就是把上個版本中mapper的sql搬到了這裏的xml中了。
3、編寫Dao層的代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
interface
UserMapper { List<UserEntity>
getAll(); UserEntity
getOne(Long id); void
insert(UserEntity user); void
update(UserEntity user); void
delete(Long id); } |
對比上一步這裏全部只剩了接口方法。
4、使用
使用和上個版本沒有任何區別,大家就看代碼吧。
如何選擇
兩種模式各有特點,註解版適合簡單快速的模式,其實像現在流行的這種微服務模式,一個微服務就會對應一個自已的數據庫,多表連接查詢的需求會大大的降低,會越來越適合這種模式。
老傳統模式比適合大型項目,可以靈活的動態生成SQL,方便調整SQL,也有痛痛快快,洋洋灑灑的寫SQL的感覺。