添加依賴
這里需要添加mybatis-spring-boot-starter依賴跟mysql依賴
<!--最新版本,匹配spring Boot1.5 or higher-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
MyBatis-Spring-Boot-Starter依賴將會(huì)提供如下:
- 自動(dòng)檢測(cè)現(xiàn)有的DataSource
- 將創(chuàng)建并注冊(cè)SqlSessionFactory的實(shí)例浩嫌,該實(shí)例使用SqlSessionFactoryBean將該DataSource作為輸入進(jìn)行傳遞
- 將創(chuàng)建并注冊(cè)從SqlSessionFactory中獲取的SqlSessionTemplate的實(shí)例檐迟。
- 自動(dòng)掃描您的mappers,將它們鏈接到SqlSessionTemplate并將其注冊(cè)到Spring上下文码耐,以便將它們注入到您的bean中追迟。
就是說(shuō),使用了該Starter之后骚腥,只需要定義一個(gè)DataSource即可(application.properties中可配置)敦间,它會(huì)自動(dòng)創(chuàng)建使用該DataSource的SqlSessionFactoryBean以及SqlSessionTemplate。會(huì)自動(dòng)掃描你的Mappers束铭,連接到SqlSessionTemplate廓块,并注冊(cè)到Spring上下文中。
數(shù)據(jù)源配置
在src/main/resources/application.properties中配置數(shù)據(jù)源信息契沫。
spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
自定義數(shù)據(jù)源
Spring Boot默認(rèn)使用tomcat-jdbc數(shù)據(jù)源带猴,如果你想使用其他的數(shù)據(jù)源,比如這里使用了阿里巴巴的數(shù)據(jù)池管理,除了在application.properties
配置數(shù)據(jù)源之外懈万,你應(yīng)該額外添加以下依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.19</version>
</dependency>
修改Application.java
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import javax.sql.DataSource;
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Autowired
private Environment env;
//destroy-method="close"的作用是當(dāng)數(shù)據(jù)庫(kù)連接不使用的時(shí)候,就把該連接重新放到數(shù)據(jù)池中,方便下次使用調(diào)用.
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));//用戶名
dataSource.setPassword(env.getProperty("spring.datasource.password"));//密碼
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setInitialSize(2);//初始化時(shí)建立物理連接的個(gè)數(shù)
dataSource.setMaxActive(20);//最大連接池?cái)?shù)量
dataSource.setMinIdle(0);//最小連接池?cái)?shù)量
dataSource.setMaxWait(60000);//獲取連接時(shí)最大等待時(shí)間拴清,單位毫秒。
dataSource.setValidationQuery("SELECT 1");//用來(lái)檢測(cè)連接是否有效的sql
dataSource.setTestOnBorrow(false);//申請(qǐng)連接時(shí)執(zhí)行validationQuery檢測(cè)連接是否有效
dataSource.setTestWhileIdle(true);//建議配置為true会通,不影響性能口予,并且保證安全性。
dataSource.setPoolPreparedStatements(false);//是否緩存preparedStatement涕侈,也就是PSCache
return dataSource;
}
}
ok這樣就算自己配置了一個(gè)DataSource苹威,Spring Boot會(huì)智能地選擇我們自己配置的這個(gè)DataSource實(shí)例。
腳本初始化
CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `spring`;
DROP TABLE IF EXISTS `learn_resource`;
CREATE TABLE `learn_resource` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`author` varchar(20) DEFAULT NULL COMMENT '作者',
`title` varchar(100) DEFAULT NULL COMMENT '描述',
`url` varchar(100) DEFAULT NULL COMMENT '地址鏈接',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1029 DEFAULT CHARSET=utf8;
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (999,'官方SpriongBoot例子','官方SpriongBoot例子','https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1000,'龍果學(xué)院','Spring Boot 教程系列學(xué)習(xí)','http://www.roncoo.com/article/detail/124661');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1001,'嘟嘟MD獨(dú)立博客','Spring Boot干貨系列','http://tengj.top/');
insert into `learn_resource`(`id`,`author`,`title`,`url`) values (1002,'后端編程嘟','Spring Boot視頻教程','http://www.toutiao.com/m1559096720023553/');
注解方式跟XML配置方式共同的模塊編碼
不管是注解方式還是XML配置的方式驾凶,以下代碼模塊都是一樣的
實(shí)體對(duì)象
public class LearnResouce {
private Long id;
private String author;
private String title;
private String url;
// SET和GET方法
}
Controller層
@Controller
public class HelloController {
@Autowired
LearnMapper learnMapper;
@RequestMapping("hello")
public ModelAndView hello(HttpServletResponse response) throws IOException {
// response.getWriter().println("hello");
LearnResouce learnResouce = new LearnResouce();
learnResouce.setAuthor("zhangsan");
learnMapper.add(learnResouce);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("hello");
modelAndView.addObject("username","zhangsan");
return modelAndView;
}
}
Mybatis集成
XML配置方式
xml配置方式保持映射文件的老傳統(tǒng)牙甫,優(yōu)化主要體現(xiàn)在不需要實(shí)現(xiàn)dao的是實(shí)現(xiàn)層调违,系統(tǒng)會(huì)自動(dòng)根據(jù)方法名在映射文件中找對(duì)應(yīng)的sql,具體操作如下:
編寫Dao層的代碼
新建LearnMapper接口且轨,無(wú)需具體實(shí)現(xiàn)類浮声。
package com.dudu.dao;
@Mapper
@Component
public interface LearnMapper {
int add(LearnResouce learnResouce);
int update(LearnResouce learnResouce);
int deleteByIds(String[] ids);
LearnResouce queryLearnResouceById(Long id);
public List<LearnResouce> queryLearnResouceList(Map<String, Object> params);
}
修改application.properties 配置文件
#指定bean所在包
mybatis.type-aliases-package=com.dudu.domain
#指定映射文件
mybatis.mapperLocations=classpath:mapper/*.xml
添加LearnMapper的映射文件
在src/main/resources目錄下新建一個(gè)mapper目錄旋奢,在mapper目錄下新建LearnMapper.xml文件。
通過(guò)mapper標(biāo)簽中的namespace屬性指定對(duì)應(yīng)的dao映射屉符,這里指向LearnMapper锹引。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dudu.dao.LearnMapper">
<resultMap id="baseResultMap" type="com.dudu.domain.LearnResouce">
<id column="id" property="id" jdbcType="BIGINT" />
<result column="author" property="author" jdbcType="VARCHAR"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="url" property="url" jdbcType="VARCHAR"/>
</resultMap>
<sql id="baseColumnList" >
id, author, title,url
</sql>
<select id="queryLearnResouceList" resultMap="baseResultMap" parameterType="java.util.HashMap">
select
<include refid="baseColumnList" />
from learn_resource
<where>
1 = 1
<if test="author!= null and author !=''">
AND author like CONCAT(CONCAT('%',#{author,jdbcType=VARCHAR}),'%')
</if>
<if test="title != null and title !=''">
AND title like CONCAT(CONCAT('%',#{title,jdbcType=VARCHAR}),'%')
</if>
</where>
</select>
<select id="queryLearnResouceById" resultMap="baseResultMap" parameterType="java.lang.Long">
SELECT
<include refid="baseColumnList" />
FROM learn_resource
WHERE id = #{id}
</select>
<insert id="add" parameterType="com.dudu.domain.LearnResouce" >
INSERT INTO learn_resource (author, title,url) VALUES (#{author}, #{title}, #{url})
</insert>
<update id="update" parameterType="com.dudu.domain.LearnResouce" >
UPDATE learn_resource SET author = #{author},title = #{title},url = #{url} WHERE id = #{id}
</update>
<delete id="deleteByIds" parameterType="java.lang.String" >
DELETE FROM learn_resource WHERE id in
<foreach item="idItem" collection="array" open="(" separator="," close=")">
#{idItem}
</foreach>
</delete>
</mapper>
使用MyBatis3提供的注解可以逐步取代XML嫌变,例如使用@Select注解直接編寫SQL完成數(shù)據(jù)查詢吨艇,使用@SelectProvider高級(jí)注解還可以編寫動(dòng)態(tài)SQL,以應(yīng)對(duì)復(fù)雜的業(yè)務(wù)需求腾啥。
一. 基礎(chǔ)注解
MyBatis 主要提供了以下CRUD注解:
@Select
@Insert
@Update
@Delete
增刪改查占據(jù)了絕大部分的業(yè)務(wù)操作东涡,掌握這些基礎(chǔ)注解的使用還是很有必要的,例如下面這段代碼無(wú)需XML即可完成數(shù)據(jù)查詢:
@Mapperpublic interface UserMapper { @Select("select * from t_user") List<User> list();}
使用過(guò)Hibernate的同學(xué)可能會(huì)好奇倘待,這里為什么沒(méi)有配置映射關(guān)系也能完成屬性注入软啼?在傳統(tǒng)項(xiàng)目中使用過(guò)Mybatis的童鞋可能很快就反應(yīng)過(guò)來(lái),是因?yàn)樵谂渲梦募虚_(kāi)啟了全局駝峰映射延柠,SpringBoot中同樣能夠做到祸挪,并且更為簡(jiǎn)單快捷。
雖然開(kāi)啟了全局駝峰映射贞间,但你可能還會(huì)質(zhì)疑贿条,如果不符合下劃線轉(zhuǎn)駝峰規(guī)則的字段,拿查詢回來(lái)的實(shí)體對(duì)象屬性將獲取為null增热,比如上述User對(duì)象屬性mobileNum和對(duì)應(yīng)的數(shù)據(jù)庫(kù)字段phoneNum整以,則查詢結(jié)果為:
[ { "userId": "1", "username": "admin", "password": "admin", "mobileNum": null }, { "userId": "2", "username": "roots", "password": "roots", "mobileNum": null }]
為了解決對(duì)象屬性和字段駝峰不一致的問(wèn)題,我們可以使用映射注解@Results來(lái)指定映射關(guān)系峻仇。
二. 映射注解
Mybatis主要提供這些映射注解:
@Results 用于填寫結(jié)果集的多個(gè)字段的映射關(guān)系.
@Result 用于填寫結(jié)果集的單個(gè)字段的映射關(guān)系.
@ResultMap 根據(jù)ID關(guān)聯(lián)XML里面<resultMap>.
例如上面的list方法公黑,我們可以在查詢SQL的基礎(chǔ)上,指定返回的結(jié)果集的映射關(guān)系摄咆,其中property表示實(shí)體對(duì)象的屬性名凡蚜,column表示對(duì)應(yīng)的數(shù)據(jù)庫(kù)字段名。
@Results({ @Result(property = "userId", column = "USER_ID"), @Result(property = "username", column = "USERNAME"), @Result(property = "password", column = "PASSWORD"), @Result(property = "mobileNum", column = "PHONE_NUM") }) @Select("select * from t_user") List<User> list();
查詢結(jié)果如下:
[ { "userId": "1", "username": "admin", "password": "admin", "mobileNum": "15011791234" }, { "userId": "2", "username": "roots", "password": "roots", "mobileNum": "18812342017" }]
為了解決對(duì)象屬性和字段駝峰不一致的問(wèn)題吭从,我們可以使用映射注解@Results來(lái)指定映射關(guān)系朝蜘。
為了方便演示和免除手工編寫映射關(guān)系的煩惱,這里提供了一個(gè)快速生成映射結(jié)果集的方法涩金,具體內(nèi)容如下:
/** * 1.用于獲取結(jié)果集的映射關(guān)系 */ public static String getResultsStr(Class origin) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("@Results({\n"); for (Field field : origin.getDeclaredFields()) { String property = field.getName(); //映射關(guān)系:對(duì)象屬性(駝峰)->數(shù)據(jù)庫(kù)字段(下劃線) String column = new PropertyNamingStrategy.SnakeCaseStrategy().translate(field.getName()).toUpperCase(); stringBuilder.append(String.format("@Result(property = \"%s\", column = \"%s\"),\n", property, column)); } stringBuilder.append("})"); return stringBuilder.toString(); }
在當(dāng)前Main方法執(zhí)行效果如下:然后我們將控制臺(tái)這段打印信息復(fù)制到接口方法上即可谱醇。
三. 高級(jí)注解
MyBatis-3 主要提供了以下CRUD的高級(jí)注解:
@SelectProvider
@InsertProvider
@UpdateProvider
@DeleteProvider
見(jiàn)名知意暇仲,這些高級(jí)注解主要用于動(dòng)態(tài)SQL副渴,這里以@SelectProvider 為例煮剧,主要包含兩個(gè)注解屬性轿秧,其中type表示工具類菇篡,method 表示工具類的某個(gè)方法驱还,用于返回具體的SQL议蟆。
@Mapperpublic interface UserMapper {
@SelectProvider(type = UserSqlProvider.class, method = "list222")
List<User> list2();
}
工具類代碼如下:
public class UserSqlProvider {
public String list222() {
return "select * from t_user ;
}
四. 詳細(xì)教程
對(duì)上述注解有所了解之后咐容,我們以具體項(xiàng)目案例來(lái)進(jìn)一步鞏固這些注解的實(shí)際使用戳粒。
1. 引入依賴
為了方便演示,首選搭建Web環(huán)境涂籽,另外數(shù)據(jù)庫(kù)選擇Mysql 5.5+评雌。
<dependencies>
<dependency>
<!--添加Web依賴 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!--添加Mybatis依賴 -->
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version>
</dependency>
<dependency>
<!--添加MySQL驅(qū)動(dòng)依賴 -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <scope>runtime</scope>
</dependency>
<dependency>
<!--添加Test依賴 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. 添加配置
這里主要是添加數(shù)據(jù)源团赏,配置駝峰映射和開(kāi)啟SQL日志的控制臺(tái)打印舔清。在項(xiàng)目的資源目錄中体谒,添加 application.yml 配置如下:
spring: datasource:
#連接MySQL
url: jdbc:mysql://localhost:3306/socks?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Drivermybatis: configuration:
#配置項(xiàng):開(kāi)啟下劃線到駝峰的自動(dòng)轉(zhuǎn)換.
作用:將數(shù)據(jù)庫(kù)字段根據(jù)駝峰規(guī)則自動(dòng)注入到對(duì)象屬性。
map-underscore-to-camel-case: truelogging: level:
#打印SQL信息
com.hehe.mapper: debug
3. 編寫數(shù)據(jù)層代碼
這里以我們熟悉的用戶信息為例幌绍,編寫UserMapper接口和本案例使用的UserSqlProvider。
3.1 UserMapper
添加UserMapper接口用于數(shù)據(jù)查詢:
package com.hehe.mapper;
@Mapperpublic interface UserMapper {
/** * 方式1:使用注解編寫SQL伪冰。 */
@Select("select * from t_user") List<User> list();
/** * 方式2:使用注解指定某個(gè)工具類的方法來(lái)動(dòng)態(tài)編寫SQL. */
@SelectProvider(type = UserSqlProvider.class, method = "listByUsername")
List<User> listByUsername(String username);
/** * 延伸:上述兩種方式都可以附加@Results注解來(lái)指定結(jié)果集的映射關(guān)系.
* * PS:如果符合下劃線轉(zhuǎn)駝峰的匹配項(xiàng)可以直接省略不寫贮聂。 */
@Results({@Result(property = "userId", column = "USER_ID"),
@Result(property = "username", column = "USERNAME"),
@Result(property = "password", column = "PASSWORD"),
@Result(property = "mobileNum", column = "PHONE_NUM") })
@Select("select * from t_user") List<User> listSample();
/** * 延伸:無(wú)論什么方式,如果涉及多個(gè)參數(shù),則必須加上@Param注解,否則無(wú)法使用EL表達(dá)式獲取參數(shù)吓懈。 */
@Select("select * from t_user where username like #{username} and password like #{password}")
User get(@Param("username") String username, @Param("password") String password);
@SelectProvider(type = UserSqlProvider.class, method = "getBadUser")
User getBadUser(@Param("username") String username, @Param("password") String password);}
3.2 UserSqlProvider
添加UserSqlProvider耻警,用于生成SQL的工具類 甘穿。
/*** 主要用途:根據(jù)復(fù)雜的業(yè)務(wù)需求來(lái)動(dòng)態(tài)生成SQL.* <p>* 目標(biāo):使用Java工具類來(lái)替代傳統(tǒng)的XML文件.(例如:UserSqlProvider.java
<-- UserMapper.xml)*/
public class UserSqlProvider {
/** * 方式1:在工具類的方法里,可以自己手工編寫SQL。 */
public String listByUsername(String username) {
return "select * from t_user where username =#{username}";
}
/** * 方式2:也可以根據(jù)官方提供的API來(lái)編寫動(dòng)態(tài)SQL式曲。 */
public String getBadUser(@Param("username") String username, @Param("password") String password) {
return new SQL() {{SELECT("*");FROM("t_user");
if (username != null && password != null) {
WHERE("username like #{username} and password like #{password}");
} else {
WHERE("1=2");
}
}}.toString();
}}
3.3 實(shí)體類User
添加實(shí)體類User
public class User {
private String userId;
private String username;
private String password;
private String mobileNum;
//Getters & Setters
}
3.4 添加數(shù)據(jù)庫(kù)記錄
打開(kāi)Navicat 查詢窗口兰伤,然后只需下面這段腳本敦腔。
USE `SOCKS`;DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` ( `USER_ID` varchar(50) , `USERNAME` varchar(50) , `PASSWORD` varchar(50) , `PHONE_NUM` varchar(15) )
;
INSERT INTO `t_user` VALUES ('1', 'admin', 'admin','15011791234');INSERT INTO `t_user` VALUES ('2', 'roots', 'roots','18812342017');
4. 編寫控制層代碼
package com.hehe.controller;
@RestController@RequestMapping("/user/*")
public class UserController {
@SuppressWarnings("all")
@Autowired
UserMapper userMapper;
@GetMapping("list")
public List<User> list() {
return userMapper.list();
}
@GetMapping("list/{username}")
public List<User> listByUsername(@PathVariable("username") String username) { return userMapper.listByUsername(username);
}
@GetMapping("get/{username}/{password}") public User get(@PathVariable("username") String username, @PathVariable("password") String password) {
return userMapper.get(username, password);
}
@GetMapping("get/bad/{username}/{password}")
public User getBadUser(@PathVariable("username") String username, @PathVariable("password") String password) {
return userMapper.getBadUser(username, password);
}}
5. 啟動(dòng)和測(cè)試
啟動(dòng)工程后找前,訪問(wèn) http://localhost:8080/user/list 可以查看用戶列表如下:
訪問(wèn) http://localhost:8080/user/list/admin 可以查詢用戶名為admin的信息: