第七章、Spring Boot MyBatis升级篇
课时二十七、Spring Boot MyBatis升级篇-注解
缘起:在一节视频中,有这么一段留言:“会不会推出SpringBoot整合Mybaits配置文件sqlMapConfig.xml搭配mapper.xml的视频呢??? 看到有这个整合直接付款来看,结果是急速开发模式,sql都写在类中了,想看配置方式的 ,大神出一个吧。”粉丝需求,那才是真的需求。
(1)MyBatis介绍
来源:MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
介绍:MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
(2)注解思路
在Spring Boot中使用注解集成MyBatis的话,那么核心的文件就是实体类和SQL的映射类,比如DemoMapper,在此类当中就是方法和对应的注解sql语句,那么要怎么能够识别到DemoMapper类呢,在Spring Boot中就特别的简单,在启动类App中加入一个注解@MapperScan(指定Mapper包路径)。
(3)新建project以及添加依赖包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
(4)创建启动类App.java
@SpringBootApplication
@MapperScan("com.kfit.*.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
(5)编写实体类Demo
public class Demo {
private int id;
private String name;
//省略getter and setter
}
(6)编写映射接口DemoMapper
public interface DemoMapper {
@Insert("insert into Demo(name) values(#{name})")
public void save(Demo demo);
}
(7)编写service类DemoService
@Service
public class DemoService {@Autowired
private DemoMapper demoMapper;
@Transactional//添加事务.
public void save(Demo demo){
demoMapper.save(demo);
}
}
(8)编写控制类DemoController
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("/save")
public Demo save(){
Demo demo = new Demo();
demo.setName("张三");
demoService.save(demo);
return demo;
}
}
(9)配置数据库连接池
########################################################
###datasource -- mysql的数据库配置.
########################################################
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
(10)测试
好了,到这里就可以启动App.java进行访问测试了,访问地址:
http://127.0.0.1:8080/save在访问之前需要注意:
(1)确保创建了数据库test;
(2)确保创建了表demo,建表语句如下:
CREATE TABLE demo (
id int NOT NULL AUTO_INCREMENT ,
name varchar(100) NULL ,
PRIMARY KEY (id)
);
访问之后,在浏览器端会看到数据:
{"id":0,"name":"张三"}
课时二十八、Spring Boot MyBatis升级篇-注解-自增ID
1、引言
在上一篇文章中,我们已经会集成MyBatic并且完成了保存数据的动作,但是现在如果你细心观察的话,在浏览器看到的数据中id=0。有人说:我不需要返回id呀,id返回我也用不到,返回为0的话,无所谓了。但是在实际项目中,我们是有很多场景需要用到返回的id的
场景
(2)场景2:在题库管理的时候,我们需要录入题目信息以及题库的选项,对于题库的选项是可以多个,如下:
题目:你最喜欢的是技术是?
A: Java语言 B: PHP语言 C: python语言 D:C语言
那么对于题目信息我们会保存到一张表中Question,对于选项,我们会保存到另外一张表QuestionOption,对于表QuestionOption会有一个外键qid,也就是question的主键。对于Question和QuestionOption的保存是在同一个请求就完成的(如果是题目的保存和选项的保存是两个请求才完成的,那么流程不一样)。在保存QuestionOption的时候,需要用到Question的主键,这时候后台的保存代码是这样的:
Question question = Question();
int qid = save(Question);
QuestionOption qo = new QuestionOption();
qo.setQid(qid);
int qid = save(QuestionOption);
2、示例代码
public interface DemoMapper {
@Insert("insert into Demo(name) values(#{name})")
@Options(keyProperty="id",keyColumn="id",useGeneratedKeys=true)
public void save(Demo demo);
}
在xml编写的时候,看看能不能加
3、@Options解说
@Options注解中的工作就比较有意思,我们在插入记录时,一般是定义主键自增(auto_increment),但是在某些情况下,我们插入一条记录后,还想得到这条记录的自增主键ID,useGeneratedKeys=true就是定义数据库返回主键ID的,常用的属性如下:
useCache=true,
flushCache=false,
resultSetType=FORWARD_ONLY,
statementType=PREPARED,
fetchSize= -1,timeout=-1 ,
useGeneratedKeys=false ,
keyProperty=”id“。
KeyProperty是实体类中定义的主键字段名;
KeyColumn是表中主键对应的字段;
useGeneratedKeys=true定义数据库返回主键ID;
注解中的useCache还可以设置缓存相关的选项:
useCache = true表示本次查询结果被缓存以提高下次查询速度,flushCache = false表示下次查询时不刷新缓存,timeout = 10000表示查询结果缓存10000秒。
参考spring-boot-mybatis
课时二十九、Spring Boot MyBatis升级篇-注解-增删改查
(1)update:修改操作
在原先的代码基础上进行编码,在DemoMapper类中加入:
@Update("update Demo set name=#{name} where id=#{id}")
public int update(@Param("id")int id,@Param("name")String name);使用@Update标明这是一个update语句,注意:在这里返回了int值,这个是值返回成功修改的数量,比如:成功找到了5条数据,并且修改成功了,那么返回值就是5。
(2)delete:查询操作
@Delete("delete from Demo where id=#{id}")
public int delete(int id);
(3)select all: 查询全部
@Select("select *from Demo")
public List<Demo> selectAll();
(4)select by id:根据id查询操作
@Select("select *from Demo where id=#{id}")
public Demo selectById(int id);
参考spring-boot-mybatis
课时三十、Spring Boot MyBatis升级篇-注解-分页查询
(1)集成原理说明
MyBatis提供了拦截器接口,我们可以实现自己的拦截器,将其作为一个plugin装入到SqlSessionFactory中。
(2)PageHelper介绍
PageHelper是Github上有位开发者写了一个分页插件,可以很方便的添加到MyBatis的拦截器接口中。
(3)集成准备
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
(4)配置文件编写
@Configuration
public class MyBatisConfiguration {
/**
* 注册MyBatis分页插件PageHelper
* @return
*/
@Bean
public PageHelper pageHelper() {
System.out.println("MyBatisConfiguration.pageHelper()");
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
(5)编码测试
这个使用起来特别的简单,只是在原来查询全部的代码之前加入一句:
PageHelper.startPage(1,2);
第一个参数是第几页;第二个参数是每页显示条数。
参考spring-boot-mybatis
课时三十一、Spring Boot MyBatis升级篇-注解-分页PageHelper不生效
开发步骤
在MyBatis中集成了PageHelper,然后也在需要使用分页的地方加入了如下代码:
PageHelper.startPage(1,2);
1、需要在pom.xml文件中添加PageHelper依赖;
2、需要配置一个MyBatisConfiguration -->注入了PageHelper;
3、需要在需要分页的查询前面使用PageHelper.startPage(pageNum,pageSize);分页
(1)原因1:mybatis-spring-boot-starter版本有误
这个可能你使用错了版本号,主要是pom.xml文件中的版本的引入,错误的版本引入:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>我在博客中已经写的很详细了,但是还是有人会掉进坑里,之所以会有这篇文章的出现就是因为已经有人已经掉进坑里了。那么正确的配置是:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
请不要使用1.0.0版本,因为还不支持拦截器插件,
1.3.0 是博主写帖子时候的版本,大家使用最新版本即可
(2)原因2:重新定义了SqlSessionFactory配置
第二种不好使的情况就是重新定义了SqlSessionFactory但是并没有配置对应的PageHelper插件,所以导致使用PageHelper.startPage(1,1); 无效,那么如果要重新定义SqlSessionFactory 的话
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Interceptor[] plugins = new Interceptor[]{pageHelper()};
sqlSessionFactoryBean.setPlugins(plugins);
// 指定mybatisxml文件路径
sqlSessionFactoryBean.setMapperLocations(resolver
.getResources("classpath:/mybatis/*.xml"));
return sqlSessionFactoryBean.getObject();
}
参考spring-boot-mybatis
课时三十二、Spring Boot MyBatis升级篇-异常:Parameter 'name' not found
错误信息:
异常信息如下:
nested exception is org.apache.ibatis.binding.BindingException: Parameter 'name' not found. Available parameters are [0, 1, param1, param2]
原因分析
出现这个异常的原因是因为你在使用@insert的使用,没有进行相应的字段对应关系。
如下的代码就会报如上的错误:
@Insert("insert into Demo(name,password) values(#{name},#{password})")
public void save(String name,String password);
解决方案
正确的代码应该如下:
@Insert("insert into Demo(name,password) values(#{name},#{password})")
public void save(@Param("name") String name,@Param("password") String password);
特殊情况
单参数特殊情况
但是如下的代码就不会报错:
@Insert("insert into Demo(name,password) values(#{name})")
public void save(String name);
当 insert 语句中只有一个参数的,对应的void save方法不需要做任何特殊处理(不需要加@Param也是可以对应上的),当有多个参数的时候,需要使用@Param注解进行字段的对应。
参考spring-boot-mybatis
课时三十三、Spring Boot MyBatis升级篇-注解- #和$符号特别篇
前言
#、$符号在MyBatis的SQL参数注入有很重要的作用,这两个符号还是需要理解清楚的,不然可能就会写出被攻击的SQL语句了。好了,这篇文章就是为了解决#、$各自的使用场景。
(1)#{}说明
使用#{}意味着使用的预编译的语句,即在使用jdbc时的preparedStatement,sql语句中如果存在参数则会使用?作占位符,我们知道这种方式可以防止sql注入,并且在使用#{}时形成的sql语句,已经带有引号,例,select * from table1 where id=#{id} 在调用这个语句时我们可以通过后台看到打印出的sql为:select * from table1 where id='2' 加入传的值为2.也就是说在组成sql语句的时候把参数默认为字符串。
(2)${}说明
使用${}时的sql不会当做字符串处理,是什么就是什么,如上边的语句:select * from table1 where id=${id} 在调用这个语句时控制台打印的为:select * from table1 where id=2 ,假设传的参数值为2。
(3)总结
从上边的介绍可以看出这两种方式的区别,我们最好是能用#{}则用它,因为它可以防止sql注入,且是预编译的,在需要原样输出时才使用${},如,
select * from ${tableName} order by ${id} 这里需要传入表名和按照哪个列进行排序 ,假如传入table1、id 则语句为:select * from table1 order by id
如果是使用#{} 则变成了select * from 'table1' order by 'id' 我们知道这样就不对了。
实例说明
使用#{}的语句:
@Select("Select * from Demo where name = #{name}")
public List<Demo> selectByName1(@Param("name") String name);
说明:这个例子创建一个预编译的语句,看起来像:select * from Demo where name = ?;
观察控制台的SQL打印:
selectByName1 : ==> Preparing: Select * from Demo where name = ?
DemoMapper.selectByName1 : ==> Parameters: 王五(String)
DemoMapper.selectByName1 : <== Total: 9
使用${}的语句:
@Select("Select * from Demo where name = '${name}'")
public List<Demo> selectByName2(@Param("name") String name);
说明:这个例子创建一个内联的语句,看起来像: select * from Demo where name = '王五';
观察控制台的打印:
DemoMapper.selectByName2 : ==> Preparing: Select * from Demo where name = '王五'
DemoMapper.selectByName2 : ==> Parameters:
DemoMapper.selectByName2 : <== Total: 9
案例
(1)例1:查询Demo表id=X的记录。
@Select("select *from where id=#{id}")
public Demo select3(int id);
(2)例2:查询Demo表的数据,并且按照指定字段id或者name降序排列。
@Select("select *from demo order by ${orderField}")//原样替换.
public Demo select4(String orderField);
(3)例3:查询Demo表的数据,并且按照指定字段id或者name升序或者降序排列。
@Select("select *from demo order by ${orderField} ${ascOrDesc}")//原样替换.
public Demo select5(@Param("orderField") String orderField, @Param("ascOrDesc") String ascOrDesc);
参考spring-boot-mybatis
课时三十四、Spring Boot MyBatis升级篇-注解-@Result
@Result 修饰返回的结果集,
如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。
这个注解相当于XML配置文件中的<ResultMap>。
(1)场景1:关联实体类属性和数据库字段 一 一对应
@Select("select *from Demo where id=#{id}")
public Demo selectById(int id);
(2)场景2:关联实体类属性部分属性和数据库字段不对应
比如Demo实体类:
private int id;
private String name;
private Date updateTime;数据库表信息:
id int
name varchar
update_time datetime@Select("select *from Demo where id=#{id}")
@Results({
@Result(property="updateTime",column="update_time")
})
public Demo selectById2(int id);
(3)场景3:在上面的基础上,性别是枚举类型
@Select("select *from Demo where id=#{id}")
@Results({
@Result(property="updateTime",column="update_time"),
@Result(property="sexEnum",column="sex_enum",javaType=SexEnum.class)
})
public Demo selectById2(int id);
注解总结
@Select 是查询类的注解,所有的查询均使用这个
@Result 修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。
@Insert 插入数据库使用,直接传入实体类会自动解析属性到对应的值
@Update 负责修改,也可以直接传入对象
@delete 负责删除
参考spring-boot-mybatis
课时三十五、Spring Boot MyBatis-注解-动态SQL(if test)-方案一:<script>
需求
网友1:这样如果是不定条件查询怎么解决呢?也就是xml中可以用if标签,注解怎么搞呢?
网友2:这动态sql用注解的方式不太方便吧!博主有好方法,请推出参照一下,一直没用注解的原因,就是动态sql没有好的方式,包括when foreach!针对简单的查询还是可以的!
需求场景
在一个表中有id,name,email我们查询的时候,希望name不为null的时候,作为查询条件,如果email不为null的时候,作为查询条件。
(1)name,email and 关系
@Select("Select * from Demo where name =#{name} and email=#{email} ")
public List<Demo> select3(Demo demo);
(2) if name !=null ,if email != null
现在我们希望的是如果name不为null的话,那么就当做条件,否则就不要当做条件;如果email不为null,那么就当做条件,否则不当做条件
解决方案
那么方案一:使用<script>
@Select("<script> " +
"SELECT * " +
"from Demo " +
" <where> " +
" 1=1" +
" <if test=\"name != null\">and name=#{name}</if> " +
" <if test=\"email != null\"> and email=#{email}</if> " +
" </where> " +
" </script> ")
public List<Demo> select4(Demo demo);
参考spring-boot-mybatis
课时三十六、Spring Boot MyBatis-注解-动态SQL(if test)-方案二:@Provider
前言
在上一个视频中,我们使用了<script>方法使用if test标签,但是怎么看代码怎么都不舒服,本篇博客使用另外一种方式解决这个问题。
课程大纲
(1)动态语言注解
对于创建动态的查的语言。MyBatis提供了多个注解如:@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider,这些都是建立动态语言和让MyBatis执行这些语言。
(2) 使用思路
对于MyBatis提供的几个@Provider,里面最主要的参数是type,也就是sql类的Calss对象,另外就是对应的方法名,我们看SelectProvider 的源代码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SelectProvider {
Class<?> type();String method();
}
所以要实现动态的SQL查询,那么大体的思路就是,编写一个SqlProvider,比如:DemoSqlProvider,在此方法中返回一条SQL语句即可。然后在Mapper类中使用@SelectProvider注解,指定provider类和对应的SQL方法。
(3)@SelectProvider小试牛刀
public String select5(Demo demo){
StringBuffer sql = new StringBuffer("select *from demo where 1=1 ");
if(demo.getName() != null){
sql.append(" and name=#{name}");
}
if(demo.getEmail() != null){
sql.append(" and email=#{email}");
}
return sql.toString();
}
(4)@SelectProvider初露锋芒
上面的代码直接纯SQL编写了,可读性还是相对差了点,MyBatis提供了SQL类(org.apache.ibatis.jdbc.SQL),可以让代码看起来更有意义。
public String select6(final Demo demo){
return new SQL(){{
SELECT("id,name,email");
FROM("demo");
if(demo.getName() != null){
WHERE("name=#{name}");
}
if(demo.getEmail() != null){
WHERE("email=#{email}");
}
}}.toString();
(5)@SelectProvider过关斩将
原以为万事大吉了,开心的不行,于是乎,信手拈来句代码,在查询代码加入:
PageHelper.startPage(1, 2); 整个代码如下:
@RequestMapping("/select6")
public List<Demo> select6(Demo demo){
PageHelper.startPage(1, 2);
return demoService.select6(demo);
}报错:
nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'providerTakesParameterObject' in 'class org.apache.ibatis.builder.annotation.ProviderSqlSource'出现以上问题,是由于我们使用的PageHelper版本导致的,升级版本即可。
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
(6)@InsertProvider
public String save3(final Demo demo){
return new SQL(){{
INSERT_INTO("demo");
//多个写法.
INTO_COLUMNS("name","email");
INTO_VALUES("#{name}","#{email}");
//条件写法.
// if(demo.getName() != null){
// VALUES("name","#{name}");
// }
// if(demo.getEmail() != null){
// VALUES("email","#{email}");
// }
}}.toString();
}
(7)@UpdateProvider
public String update2(final Demo demo){
return new SQL(){{
UPDATE("demo");
//条件写法.
if(demo.getName() != null){
SET("name=#{name}");
}
if(demo.getEmail() != null){
SET("email=#{email}");
}
WHERE("id=#{id}");
}}.toString();
}
(8)@DeleteProvider
public String delete2(){
return new SQL(){{
DELETE_FROM("demo");
WHERE("id=#{id}");
}}.toString();
}
Spring Boot MyBatis升级篇-注解-动态SQL-参数问题
(1)0个参数(无参数)@SelectProvider方法
public String selectNoParams(){
return new SQL(){{
SELECT("*");
FROM("demo");
}}.toString();
}
(2)1个参数的@SelectProvider方法
public String selectParams1(){
return new SQL(){{
SELECT("*");
FROM("demo");
WHERE("id=#{id}");
}}.toString();
}
(3)多参数的@SelectProvider方法(未使用@Param)
public String selectParamsMore(final Map<String,Object> map){
System.out.println(map);
return new SQL(){{
SELECT("*");
FROM("demo");
if(map.get("name") != null){
WHERE("name=#{name}");
}
if(map.get("email") != null){
WHERE("email=#{email}");
}
}}.toString();
}
(4)多参数的@SelectProvider方法(使用@Param)
(5)对象参数的@SelectProvider方法
参考spring-boot-mybatis
课时三十七、Spring Boot MyBatis升级篇-注解-特别篇:@MapperScan和@Mapper
前言
在之前的文章中,我们定义DemoMapper类,但是并没有在该类上定义类似@Service或者@Controller之类的注解,那么为什么可以被Spring管理呢?
(1)方式一:使用@Mapper注解
@Mapper : 已经使用@MapperScan进行包路径的指定.
直接在Mapper类上面添加注解@Mapper,这种方式要求每一个mapper类都需要添加此注解
(2)方式二:使用@MapperScan注解
@MapperScan("com.kfit.*.mapper") //需要指定包名。
@MapperScan({"com.kfit.*.mapper","org.kfit.*.mapper"})
参考spring-boot-mybatis
课时三十八、Spring Boot MyBatis升级篇-XML
课程大纲
(1)MyBatis介绍
来源:MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
介绍:MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
(2)配置思路
在Spring Boot中使用xml集成MyBatis的话,那么核心的文件就是实体类和SQL的映射类,比如DemoMapper,在此类当中就是普通的接口即可,那么对应SQL配置文件在Demo.xml中,那么要怎么能够识别到DemoMapper类呢,使用@MapperScan();在Demo.xml中使用<mapper> 的 namespace属性进行指定指定xml文件和mapper的对应关系,那么现在的问题就是如何识别到Demo.xml配置文件呢,这个就很简单了,在application.properties文件中配置mapper的位置即可,形如:mybatis.mapper-locations=classpath:mybatis/mapper/*.xml。
根据以上的思路,那我们编码大概的思路就是:
(a)编写实体类Demo;
(b)编写配置文件Demo.xml,主要是SQL;
(c)编写DemoMapper和Demo是对应的,在Service层就可以调用DemoMapper;
(d)在application.properties文件中配置Demo.xml文件的路径;
(3)新建project以及添加依赖包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql 数据库驱动. -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- spring-boot mybatis依赖:
请不要使用1.0.0版本,因为还不支持拦截器插件,
-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
(4)创建启动类App.java
@SpringBootApplication
@MapperScan("com.kfit.*.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
(5)编写实体类Demo
public class Demo {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(6)编写application配置文件,指定xml路径
########################################################
###datasource -- mysql的数据库配置.
########################################################
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
########################################################
###mybatis配置.
########################################################
mybatis.mapper-locations=classpath:com/kfit/*/mapper/*.xml
(7)编写映射接口DemoMapper和XML
编写XML文件,Demo.xml:
<?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.kfit.demo.mapper.DemoMapper">
<!-- insert 语句. -->
<insert id="save" parameterType="com.kfit.demo.bean.Demo" useGeneratedKeys="true" keyProperty="id">
insert into demo (name) values (#{name})
</insert>
</mapper>编写DemoMapper接口:
package com.kfit.demo.mapper;
public interface DemoMapper {
public void save(Demo demo);
}
(8)编写service类DemoService
@Service
public class DemoService {
@Autowired
private DemoMapper demoMapper;
@Transactional
public void save(Demo demo){
demoMapper.save(demo);
}
}
(9)编写控制类DemoController
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
// http://127.0.0.1:8080/save
@RequestMapping("/save")
public Demo save(){
Demo demo = new Demo();
demo.setName("张三");
demoService.save(demo);
return demo;
}
}
(10)测试
启动,访问地址:http://127.0.0.1:8080/save
Spring Boot MyBatis升级篇-XML-自增ID
<insert id="save" parameterType="com.kfit.demo.bean.Demo" useGeneratedKeys="true" keyProperty="id">
insert into
demo
(name)
values
(#{name})
</insert>
参考spring-boot-mybatis-xml
课时三十九、 Spring Boot MyBatis升级篇-XML-增删改查
(1)update:修改操作
在原先的代码基础上进行编码,在Demo.xml中加入:
<update id="update">
update demo set name = #{name} where id = #{id}
</update>
在DemoMapper中加入如下代码:
public int update(@Param("id")int id,@Param("name")String name);
注意:在这里返回了int值,这个是值返回成功修改的数量,比如:成功找到了5条数据,并且修改成功了,那么返回值就是5。
(2)delete:查询操作
在Demo.xml文件中加入:
<delete id="delete">
delete from demo where id = #{id}
</delete>
在DemoMapper中加入:
public int delete(int id);
注意:返回值代表成功删除了多少条数据。
(3)select all: 查询全部
在Demo.xml中加入:
<resultMap id="baseResultMap" type="com.kfit.demo.bean.Demo" >
<id property="id" column="id" />
<result property="name" column="name" />
</resultMap
<select id="selectAll" resultMap="baseResultMap">
select *from demo
</select>
在DemoMapper类中加入:
public List<Demo> selectAll();
使用@Select注明这是select语句。
(4)select by id:根据id查询操作
在Demo.xml文件中加入:
<select id="selectById" resultMap="baseResultMap">
select *from demo where id = #{id}
</select>
在DemoMapper类中加入:
public Demo selectById(int id);
(5)update题外话
在DemoMapper中,update是指定了多个参数,但是实际中一个实体类中会有很多的字段,这种方式,总感觉不是很好,那么有更好的方式呢,有的,如下的写法:
原先写法:
public int update(@Param("id")int id,@Param("name")String name);
对象写法:
public int update(Demo demo);
修改完之后瞬间清爽了很多,但是原先的写法也是需要会的,使用场景,比如:我们要修改状态status的话,那么使用updateStatus(int id,int status)的方式,直接指定会更好。
(6)代码
public interface DemoMapper {
public int save(Demo demo);
public int update(@Param("id")int id,@Param("name")String name);
public int delete(int id);
public List<Demo> selectAll();
public Demo selectById(int id);
}
参考spring-boot-mybatis-xml
课时四十、Spring Boot MyBatis升级篇-XML-分页查询
(1)集成原理说明
MyBatis提供了拦截器接口,我们可以实现自己的拦截器,将其作为一个plugin装入到SqlSessionFactory中。
(2)PageHelper介绍
PageHelper是Github上有位开发者写了一个分页插件,可以很方便的添加到MyBatis的拦截器接口中。Github项目地址: https://github.com/pagehelper/Mybatis-PageHelper
(3)集成准备
集成PageHelper很简单,只需要在pom.xml文件中添加如下依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
(4)配置文件编写
@Configuration
public class MyBatisConfiguration {
/**
* 注册MyBatis分页插件PageHelper
* @return
*/
@Bean
public PageHelper pageHelper() {
System.out.println("MyBatisConfiguration.pageHelper()");
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
(5)编码测试
这个使用起来特别的简单,只是在原来查询全部的代码之前加入一句:
PageHelper.startPage(1,2);
第一个参数是第几页;第二个参数是每页显示条数。
参考spring-boot-mybatis-xml
课时四十一、 Spring Boot MyBatis升级篇-XML-分页PageHelper不生效
现象
在MyBatis中集成了PageHelper,然后也在需要使用分页的地方加入了如下代码:
PageHelper.startPage(1,2);
但是就是不生效呢
原因
(1)原因1:mybatis-spring-boot-starter版本有误
那么正确的配置是:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
请不要使用1.0.0版本,因为还不支持拦截器插件,
1.3.0 是博主写帖子时候的版本,大家使用最新版本即可
(2)原因2:重新定义了SqlSessionFactory配置
第二种不好使的情况就是重新定义了SqlSessionFactory但是并没有配置对应的PageHelper插件,所以导致使用PageHelper.startPage(1,1); 无效,那么如果要重新定义SqlSessionFactory 的话,那么以下代码可以作为一个参考,其中红色部分是需要注意的地方:
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Interceptor[] plugins = new Interceptor[]{pageHelper()};
sqlSessionFactoryBean.setPlugins(plugins);
// 指定mybatisxml文件路径
sqlSessionFactoryBean.setMapperLocations(resolver
.getResources("classpath:/mybatis/*.xml"));
return sqlSessionFactoryBean.getObject();
}
总结
总结下这个问题,其一引入了错误的mybatis-spring-boot-starter版本,引用正确的版本即可; 其二就是重新定义SqlSessionFactory了,需要配置对应的PageHelper插件。
参考spring-boot-mybatis-xml
课时四十二、Spring Boot MyBatis升级篇-XML-动态SQL(if test)
(1)if标签
if标签可用在许多类型的sql语句中,我们以查询为例。首先看一个很普通的查询:
<select id="select1" resultMap="baseResultMap">
select *from demo where
name = #{name} and email = #{email}
</select>
但是此时如果name或email为null,此语句很可能报错或查询结果为空。此时我们使用if动态sql语句先进行判断,如果值为null或等于空字符串,我们就不进行此条件的判断,增加灵活性Demo.xml代码修改为使用if test:
<select id="select1" resultMap="baseResultMap">
select *from demo where
<if test="name != null and name != ''">
name = #{name}
</if>
<if test="email != null and email != ''">
and email=#{email}
</if>
</select>
(2)if+where的条件判断
解决的问题
当where中的条件使用的if标签较多时,这样的组合可能会导致错误。上面的查询语句中,当访问:http://127.0.0.1:8080/select1?email=aa@qq.com 参数name为null,将不会进行name列的判断,则会直接导“WHERE AND”关键字多余的错误SQL。
这时我们可以使用where动态语句来解决。这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
解决的方案
上面的<select>修改为如下:
<select id="select1" resultMap="baseResultMap">
select *from demo
<where>
<if test="name != null and name != ''">
name = #{name}
</if>
<if test="email != null and email != ''">
and email=#{email}
</if>
</where>
</select>
(3)if+set的更新语句
解决的问题
当update语句中没有使用if标签时,如果有一个参数为null,都会导致错误。
当在update语句中使用if标签时,如果前面的if没有执行,则会导致逗号多余错误。使用set标签可以将动态的配置SET 关键字,和剔除追加到条件末尾的任何不相关的逗号。
使用if+set标签修改后,如果某项为null则不进行更新,而是保持数据库原值。如下示例
解决的方案
<update id="update1">
update demo
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="email != null and email != ''">
email=#{email}
</if>
</set>
where id = #{id}
</update>这样就可以单独修改name或者email,或者是同时修改name和email,但是需要注意,如果什么都不修改的话是会报错的。
(4)if+trim代替where/set标签
trim是更灵活的去处多余关键字的标签,它可以实践where和set的效果。
<select id="select2" resultMap="baseResultMap">
select *from demo
<trim prefix="where" prefixOverrides="and|or">
<if test="name != null and name != ''">
name = #{name}
</if>
<if test="email != null and email != ''">
and email=#{email}
</if>
</trim>
</select><update id="update2">
update demo
<trim prefix="set" suffixOverrides=",">
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="email != null and email != ''">
email=#{email}
</if>
</trim>
where id = #{id}
</update>
(5)choose (when, otherwise)
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。而使用if标签时,只要test中的表达式为true,就会执行if标签中的条件。MyBatis提供了choose 元素。if标签是与(and)的关系,而choose标签是或(or)的关系。
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行otherwise中的sql。类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。
例如下面例子,同样把所有可以限制的条件都写上,方面使用。choose会从上到下选择一个when标签的test为true的sql执行。安全考虑,我们使用where将choose包起来,放置关键字多于错误。
<select id="select3" resultMap="baseResultMap">
select *from demo
<where>
<choose>
<when test="name != null and name != ''">
name = #{name}
</when>
<when test="email != null and email != ''">
and email=#{email}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
(6)foreach
说明
对于动态SQL 非常必须的,主是要迭代一个集合,通常是用于IN 条件。List 实例将使用“list”做为键,数组实例以“array” 做为键。
foreach元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
注意:你可以传递一个List实例或者数组作为参数对象传给MyBatis。当你这么做的时候,MyBatis会自动将它包装在一个Map中,用名称在作为键。List实例将会以“list”作为键,而数组实例将会以“array”作为键。
(6.1)参数为array示例的写法
接口方法的声明:
/**foreach: 参数为array示例的写法*/
public List<Demo> select3(String[] ids);
动态SQL语句:
<select id="select4" resultMap="baseResultMap">
select *from demo where id in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
(6.2)参数为List示例的写法
接口方法声明:
/**foreach: 数为list示例的写法*/
public List<Demo> select5(List<Integer> list);
动态SQL语句:
<select id="select5" resultMap="baseResultMap">
select *from demo where id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
参考spring-boot-mybatis-xml
课时四十三、Spring Boot MyBatis升级篇-XML-注解-初尝试
前言:在前面算是比较详细的介绍了mybatis的使用,那么我们还会有疑问,xml配置方式和注解方式是否共同使用呢?
可以使用,但是最好不要混用,代码维护起来不方便
参考spring-boot-mybatis-xml
课时四十四、MyBatis pagehelper替换为pagehelper-spring-boot-starter
对于Spring Boot中使用Pagehelper,现在开放了一个pagehelper-spring-boot-starter,能够更简单的进行集成,这个start(1.1.3版本)使用的是5.0.4的pagehelper。那么如何使用呢
第一步:pom.xml依赖替换
添加如下的依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.1.3</version>
</dependency>
第二步:删除配置类MyBatisConfiguration
之前在这个类里面我们注入了PageHelper,这里可以直接把这个配置类删除掉了,用不上了。
第三步:在application.properties添加配置信息
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
参考spring-boot-mybatis-xml
第七章、Spring Boot MyBatis升级篇相关推荐
- 54. spring boot日志升级篇—logback【从零开始学Spring Boot】
在<44. Spring Boot日志记录SLF4J>章节中有关相关的介绍,这里我们在深入的了解下logback框架. 为什么要使用logback ? --在开发中不建议使用System. ...
- 19年8月 字母哥 第一章 spring boot 2.x基础及概念入门 这里全部看完了 热部署没出来 第二章在前面2页 用热点公司网不行
http://springboot.zimug.com/1233100 文档 http://www.zimug.com/page/5 字母哥个人博客 11111 第一章 spring bo ...
- spring Boot 2 基础篇 。内含 整合一个spring boot 的 小案例
目录 springBoot2基础篇 前言与开发环境 一.快速创建Boot项目 1.使用spring提供的快速构建 2.基于maven的手动构建 3.在Idea中隐藏指定文件/文件夹 二.SpringB ...
- 【Spring boot】IDEA + Maven + Spring Boot + Mybatis + Druid + PageHelper
在第一篇Spring Boot 框架搭建博客中,底层用的是jpa,这篇博客底层选择的mybatis,之前搭建过Spring Boot + Mybatis的框架,用的是Spring Boot 1.5.9 ...
- Spring boot Mybatis 整合(注解版)
之前写过一篇关于springboot 与 mybatis整合的博文,使用了一段时间spring-data-jpa,发现那种方式真的是太爽了,mybatis的xml的映射配置总觉得有点麻烦.接口定义和映 ...
- Spring boot Mybatis 整合(完整版)
Spring boot Mybatis 整合(完整版) 更多干货 SpringBoot系列目录 正题 本项目使用的环境: 开发工具:Intellij IDEA 2017.1.3 springboot: ...
- 第五章 Spring Boot的数据库编程
若有错,请指出 第二章 搭建Springboot环境,配置视图解析器jsp页面 第三章 全注解下的Spring Ioc 第四章 约定编程-Spring AOP 第五章 Spring Boot的数据库编 ...
- Spring Boot 2.0 配置图文教程第 2 章 Spring Boot 配置## 书信息 demo.book.name=[Spring Boot 2.x Core Action] demo.b
本章内容 1.自定义属性快速入门 2.外化配置 3.自动配置 4.自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 第 2 章 Spring B ...
- Spring Boot+MyBatis Plus+JWT 问卷系统!开源!
你好呀,我是 Guide!这里是 JavaGuide 的「优质开源项目推荐」第 8 期,每一期我都会精选 5 个高质量的 Java 开源项目. 时间过的真快,不知不觉「优质开源项目推荐」系列已经持续半 ...
最新文章
- 终于还是对“带薪拉SHI”出手了...
- vsc提示只有一行_Solution:连续调用BAPI出错,以及BAPI提示成功但数据库没有数据...
- 不要直接对Request.Headers[If-Modified-Since]使用Convert.ToDateTime
- as常用固定搭配_英语考试干货!205个常用介词固定搭配
- 牛客题霸 [ 旋转数组的最小数字] C++题解/答案
- 云南“轮椅学子”博士毕业,清华校长俯身与他合影,他的妈妈被全网刷屏!...
- 扫盲贴|如何评价一款App的稳定性和质量?
- 设计模式学习总结(一)——设计原则与UML统一建模语言
- 阻止jQuery事件冒泡
- csapp 深入理解计算机系统 csapp.h csapp.c文件配置
- 微信公众号Web页面CSS文件里面的样式不加载
- Introduction to Materials Management 学习笔记
- 卡尔曼滤波算法_GPS定位笔记3 (卡尔曼滤波定位算法)
- [转载] 【C/C++】Vector的创建与初始化方法
- Mindomo Desktop for mac(思维导图软件)中文版
- Illustrator 教程,在 Illustrator 中了解图层
- 淘宝店铺首页全屏轮播图制作
- 如何使用电脑的切屏快捷键
- php公众号关注自动回复内容,微信公众号自动回复内容大全集锦
- 最简单的全球基站定位接口API
热门文章
- paper 43 :ENDNOTE下载及使用方法简介
- 90%AI企业都亏损?阿里、华为等高管来苏畅谈人工智能
- 神经网络的具体应用实例,各种神经网络的应用
- unity 编辑器窗口 批量修改文件名字
- 音乐服务器制作教程,让NAS做音乐服务器
- 牛人的博客(图像处理,机器视觉,机器学习等)
- 学习+思考+总结+分享
- 中大新华计算机科学与技术,专业评估|信息科学学院电子信息科学与技术、计算机科学与技术、软件工程、数字媒体技术专业评估考察会议举行...
- “转行做程序员”很难?这里有4个建议
- 视频教程-大数据搜索技术-大数据