第七章、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以及添加依赖包

    
        org.springframework.boot
        spring-boot-starter-parent
        1.4.1.RELEASE
    

 

(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 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)集成准备


    com.github.pagehelper
    pagehelper
4.1.0

(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文件中的版本的引入,错误的版本引入:

        org.mybatis.spring.boot
        mybatis-spring-boot-starter
        1.0.0
   

我在博客中已经写的很详细了,但是还是有人会掉进坑里,之所以会有这篇文章的出现就是因为已经有人已经掉进坑里了。那么正确的配置是:

        org.mybatis.spring.boot
        mybatis-spring-boot-starter
        1.3.0

请不要使用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 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 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配置文件中的

(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)-方案一: ")
    public List select4(Demo demo);

参考spring-boot-mybatis

课时三十六、Spring Boot MyBatis-注解-动态SQL(if test)-方案二:@Provider

前言

在上一个视频中,我们使用了

你可能感兴趣的:(Java学习,框架,spring-boot)