课时二十七、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升级篇相关推荐

  1. 54. spring boot日志升级篇—logback【从零开始学Spring Boot】

    在<44. Spring Boot日志记录SLF4J>章节中有关相关的介绍,这里我们在深入的了解下logback框架. 为什么要使用logback ? --在开发中不建议使用System. ...

  2. 19年8月 字母哥 第一章 spring boot 2.x基础及概念入门 这里全部看完了 热部署没出来 第二章在前面2页 用热点公司网不行

    http://springboot.zimug.com/1233100   文档 http://www.zimug.com/page/5     字母哥个人博客 11111 第一章 spring bo ...

  3. spring Boot 2 基础篇 。内含 整合一个spring boot 的 小案例

    目录 springBoot2基础篇 前言与开发环境 一.快速创建Boot项目 1.使用spring提供的快速构建 2.基于maven的手动构建 3.在Idea中隐藏指定文件/文件夹 二.SpringB ...

  4. 【Spring boot】IDEA + Maven + Spring Boot + Mybatis + Druid + PageHelper

    在第一篇Spring Boot 框架搭建博客中,底层用的是jpa,这篇博客底层选择的mybatis,之前搭建过Spring Boot + Mybatis的框架,用的是Spring Boot 1.5.9 ...

  5. Spring boot Mybatis 整合(注解版)

    之前写过一篇关于springboot 与 mybatis整合的博文,使用了一段时间spring-data-jpa,发现那种方式真的是太爽了,mybatis的xml的映射配置总觉得有点麻烦.接口定义和映 ...

  6. Spring boot Mybatis 整合(完整版)

    Spring boot Mybatis 整合(完整版) 更多干货 SpringBoot系列目录 正题 本项目使用的环境: 开发工具:Intellij IDEA 2017.1.3 springboot: ...

  7. 第五章 Spring Boot的数据库编程

    若有错,请指出 第二章 搭建Springboot环境,配置视图解析器jsp页面 第三章 全注解下的Spring Ioc 第四章 约定编程-Spring AOP 第五章 Spring Boot的数据库编 ...

  8. 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 ...

  9. Spring Boot+MyBatis Plus+JWT 问卷系统!开源!

    你好呀,我是 Guide!这里是 JavaGuide 的「优质开源项目推荐」第 8 期,每一期我都会精选 5 个高质量的 Java 开源项目. 时间过的真快,不知不觉「优质开源项目推荐」系列已经持续半 ...

最新文章

  1. 终于还是对“带薪拉SHI”出手了...
  2. vsc提示只有一行_Solution:连续调用BAPI出错,以及BAPI提示成功但数据库没有数据...
  3. 不要直接对Request.Headers[If-Modified-Since]使用Convert.ToDateTime
  4. as常用固定搭配_英语考试干货!205个常用介词固定搭配
  5. 牛客题霸 [ 旋转数组的最小数字] C++题解/答案
  6. 云南“轮椅学子”博士毕业,清华校长俯身与他合影,他的妈妈被全网刷屏!...
  7. 扫盲贴|如何评价一款App的稳定性和质量?
  8. 设计模式学习总结(一)——设计原则与UML统一建模语言
  9. 阻止jQuery事件冒泡
  10. csapp 深入理解计算机系统 csapp.h csapp.c文件配置
  11. 微信公众号Web页面CSS文件里面的样式不加载
  12. Introduction to Materials Management 学习笔记
  13. 卡尔曼滤波算法_GPS定位笔记3 (卡尔曼滤波定位算法)
  14. [转载] 【C/C++】Vector的创建与初始化方法
  15. Mindomo Desktop for mac(思维导图软件)中文版
  16. Illustrator 教程,在 Illustrator 中了解图层
  17. 淘宝店铺首页全屏轮播图制作
  18. 如何使用电脑的切屏快捷键
  19. php公众号关注自动回复内容,微信公众号自动回复内容大全集锦
  20. 最简单的全球基站定位接口API

热门文章

  1. paper 43 :ENDNOTE下载及使用方法简介
  2. 90%AI企业都亏损?阿里、华为等高管来苏畅谈人工智能
  3. 神经网络的具体应用实例,各种神经网络的应用
  4. unity 编辑器窗口 批量修改文件名字
  5. 音乐服务器制作教程,让NAS做音乐服务器
  6. 牛人的博客(图像处理,机器视觉,机器学习等)
  7. 学习+思考+总结+分享
  8. 中大新华计算机科学与技术,专业评估|信息科学学院电子信息科学与技术、计算机科学与技术、软件工程、数字媒体技术专业评估考察会议举行...
  9. “转行做程序员”很难?这里有4个建议
  10. 视频教程-大数据搜索技术-大数据