整合MyBatis
MyBatis是一款优秀的持 久层框架,原名叫作iBaits, 2010 年由ApacheSoftwareFoundation迁移到Google Code并改名为MyBatis,2013年,又迁移到GitHub.上。MyBatis 支持定制化SQL、存储过程以及高级映射。MyBatis几乎避免了所有的JDBC代码手动设置参数以及获取结果集。在传统的SSM框架整合中,使用MyBatis需要大量的XML配置,而在Spring Boot 中,MyBatis 官方提供了一套自动化配置方案,可以做到MyBatis开箱即用。具体使用步骤如下。
1. 创建项目
创建Spring Boot项目,添加MyBatis依赖、数据库驱动依赖以及数据库连接池依赖,代码如下:
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 创建表
在数据库中创建表,代码如下:
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`author` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `book` VALUES (1, '三国演义', '罗贯中');
INSERT INTO `book` VALUES (2, '水浒传', '施耐庵');
创建数据库,在库中创建book表,同时添加两条测试语句。
3. 数据库配置
在中配置数据库基本连接信息:
spring:
datasource:
username: admin
password: 123456
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://120.55.61.170:3306/suohechuan?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name:
type:
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
4. 创建实体类
创建Book实体类,代码如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Book {
private Integer id;
private String name;
private String author;
}
5. 创建数据库访问层
创建BookMapper,代码如下:
@Mapper
public interface BookMapper {
int addBook (Book book) ;
int deleteBookById (Integer id) ;
int updateBookById(Book book) ;
Book getBookById() ;
List<Book> getAllBooks() ;
}
代码解释:
- 在项目的根包下 面创建-一个子 包Mapper,在Mapper中创建BookMapper.
- 有两种方式指明该类是一个 Mapper: 第-种如前面的代码所示,在BookMapper. 上 添加@Mapper注解,表明该接口是一个MyBatis中的Mapper,这种方式需要在每一个Mapper上都添加注解;还有一种简单的方式是在配置类(比如@SpringBootApplication上面)上添加@MapperScan(“”)注解,表示扫描 包下的所有接口作为Mapper, 这样就不需要在每个接口上配置@Mapper注解了。
6. 创建
在与BookMapper相同的位置创建文件,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/">
<mapper namespace= "">
<insert id="addBook" parameterType= "">
INSERT INTO book (name, author) VALUES (# {name}, # {author})
</insert>
<delete id="deleteBookById" parameterType="int">
DELETE FROM book WHERE id=#{id}
</delete>
<update id="updateBookById" parameterType="">
UPDATE book set name=# { name }, author=# {author} WHERE id=#{id}
</update>
<select id="getBookById" parameterType="int" resultType="">
SELECT * FROM book WHERE id=#{id}
</select>
<select id="getAllBooks" resultType="">
SELECT * FROM book
</select>
</mapper>
代码解释:
- 针对 BookMapper接口中的每一个方法都在中列出了实现。
- #{}用来代替接口中的参数,实体类中的属性可以直接通过#{实体类属性名}获取。
7. 创建Service和Controller
创建BookService与BookController,代码如下:
@Service
public class BookService {
@Autowired
BookMapper bookMapper;
public int addBook(Book book) {
return bookMapper.addBook(book);
}
public int updateBook(Book book) {
return bookMapper.updateBookById(book);
}
public int deleteBookById(Integer id) {
return bookMapper.deleteBookById(id);
}
public Book getBookById(Integer id) {
return bookMapper.getBookById(id);
}
public List<Book> getAllBooks() {
return bookMapper.getAllBooks();
}
}
@RestController
public class BookController {
@Autowired
BookService bookService;
@GetMapping("/bookOps")
public void bookOps() {
Book b1 = new Book();
b1.setName("西厢记");
b1.setAuthor("王实甫");
int i = bookService.addBook(b1);
System.out.println("addBook>>>" + i);
Book b2 = new Book();
b2.setId(1);
b2.setName("朝花夕拾");
b2.setAuthor("鲁迅");
int updateBook = bookService.updateBook(b2);
System.out.println("updateBook>>" + updateBook);
Book b3 = bookService.getBookById(1);
System.out.println("getBookById>>>" + b3);
int delete = bookService.deleteBookById(2);
System.out.println("deleteBookById>>" + delete);
List<Book> allBooks = bookService.getAllBooks();
System.out.println("getAllBooks>>>" + allBooks);
}
}
8. 配置文件
在Maven工程中,XML配置文件建议写在resources目录下,但是上文的文件写在包下,Maven在运行时会忽略包下的XML文件,因此需要在文件中重新指明资源文件位置,配置如下:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
<includes>
<include>**/*</include>
</includes>
</resources>
</build>
为了让dao可以找到xml文件,还需要在中加入
-aliases-package=
-locations=com/example/testspringboot/mapper1/*.xml,com/example/testspringboot/mapper2/*.xml
-locations=classpath:mapper/*.xml
#SpringBoot 开启 Mybatis 日志
=debug
#注意:其中是Mapper包位置 ,等号后面是日志等级。
接下来在浏览器中输入“http://localhost:8080/bookOps" ,即可看到数据库中数据的变化,控制台也打印出相应的日志。
addBook>>>1
updateBook>>1
getBookById>>>Book(id=1, name=朝花夕拾, author=鲁迅)
deleteBookById>>1
getAllBooks>>>[Book(id=1, name=朝花夕拾, author=鲁迅), Book(id=7, name=西厢记, author=王实甫)]
通过上面的例子可以看到,MyBatis 基本上实现了开箱即用的特性。自动化配置将开发者从繁杂的配置文件中解脱出来,以专注于业务逻辑的开发。
MyBatis多数据源
JdbcTemplate可以配置多数据源,MyBatis 也可以配置,但是步骤要稍微复杂一些。
1. 创建数据库
创建两个数据库。两个库中都创建book表,再各预设1条数据,创建脚本如下:
第一个数据库中
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`author` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `book` VALUES (1, '三国演义', '罗贯中');
第二个数据库中
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`author` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `book` VALUES (1, '水浒传', '施耐庵');
2. 创建项目
创建Spring Boot Web项目,添加如下依赖:
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
注意这里添加的数据库连接池依赖是druid-spring-boot-starter。 druid-spring-boot-starter 可以帮助开发者在SpringBoot项目中轻松集成Druid数据库连接池和监控。
3. 配置数据库连接
在中配置数据库连接信息,代码如下:
spring:
datasource:
#数据源1
one:
username: admin
password: 123456
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://120.55.61.170:3306/suohechuan?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name:
type:
#数据源2
two:
username: fristweb
password: dTNFJW4B5MrwT4KS
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://120.55.61.170:3306/fristweb?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name:
type:
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
配置两个数据源,区别主要是数据库不同,其他都是一样的。
4. 配置数据源
创建DataSourceConfig配置数据源,根据中的配置生成两个数据源:
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("")
DataSource dsOne(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("")
DataSource dsTwo(){
return DruidDataSourceBuilder.create().build();
}
}
代码解释:
- DataSourceConfig中提供了两个数据源: dsOne 和dsTwo,默认方法名即实例名。
- @ConfigurationProperties 注解表示使用不同前缀的配置文件来创建不同的DataSource实例。
5.创建MyBatis配置
配置MyBatis,主要提供SqlSessionFactory实例和SqlSessionTemplate实例,代码如下:
@Configuration
@MapperScan(value = ".mapper1",sqlSessionFactoryRef ="sqlSessionFactoryBean1")
public class MyBatisConfigOne {
@Autowired
@Qualifier("dsOne")
DataSource dsOne;
@Bean
SqlSessionFactory sqlSessionFactoryBean1() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dsOne);
return factoryBean.getObject();
}
@Bean
SqlSessionTemplate sqlSessionTemplate1() throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryBean1());
}
}
代码解释:
- 在@MapperScan 注解中指定Mapper接口所在的位置,同时指定SqlSessionFactory的实例名,则该位置下的Mapper将使用SqlSessionFactory 实例。
- 提供SqlSessionFactory 的实例,直接创建出来,同时将DataSource 的实例设置给SqlSessionFactory,这里创建的SqlSessionFactory 实例也就是@MapperScan注解中sqlSessionFactoryRef参数指定的实例。
- 提供一个SqlSessionTemplate 实例。这是一个线程安全类,主要用来管理MyBatis 中的SqlSession操作。
当MyBatisConfigOne创建成功后,参考MyBatisConfigOne 创建MyBatisConfigTwo,代码如下:
@Configuration
@MapperScan(value = ".mapper2",sqlSessionFactoryRef ="sqlSessionFactoryBean2")
public class MyBatisConfigTwo {
@Autowired
@Qualifier("dsTwo")
DataSource dsTwo;
@Bean
SqlSessionFactory sqlSessionFactoryBean2() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dsTwo);
return factoryBean.getObject();
}
@Bean("sqlSessionFactoryBean2")
SqlSessionTemplate sqlSessionTemplate2() throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryBean2());
}
}
6. 创建Mapper
分别在.mapper1和.mapper2包下创建两个不同的Mapper以及相应的Mapper映射文件,代码如下。
中:
public interface BookMapper {
List<Book> getAllBooks() ;
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/">
<mapper namespace= ".">
<select id="getAllBooks" resultType="">
select * from book;
</select>
</mapper>
org. sang.mapper2中:
public interface BookMapper2 {
List<Book> getAllBooks () ;
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/">
<mapper namespace= ".mapper2.BookMapper2">
<select id="getAllBooks" resultType="">
select * from book;
</select>
</mapper>
这两个不同的Mapper将操作不同的数据源。
7. 创建Controller
简便起见,这里直接将Mapper注入Controller中,代码如下:
@RestController
public class BookController {
@Autowired
BookMapper bookMapper;
@Autowired
BookMapper2 bookMapper2;
@GetMapping("/test1")
public void test1() {
List<Book> books1 = bookMapper.getAllBooks();
List<Book> books2 = bookMapper2.getAllBooks();
System.out.println("books1:" + books1);
System.out.println("books2 :" + books2);
}
}
在Controller中注入两个不同的Mapper,然后调用两个Mapper中的查询方法。
8. 配置文件
在Maven工程中,XML配置文件建议写在resources目录下,但是上文的文件写在包下,Maven在运行时会忽略包下的XML文件,因此需要在文件中重新指明资源文件位置,配置如下:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
<includes>
<include>**/*.xml</include>
</includes>
</resources>
</build>
为了让dao可以找到xml文件,还需要在中加入
-aliases-package=
-locations=com/example/testspringboot/mapper1/*.xml,com/example/testspringboot/mapper2/*.xml
-locations=classpath:mapper/*.xml
7. 测试
最后,在浏览器地址栏输入“http://localhost:8080/test1",控制台打印日志。JdbcTemplate多数据源配置成功。
books1:[Book(id=1, name=三国演义, author=罗贯中)]
books2: [Book(id=2, name=水浒传, author=施耐庵)]