1. 程式人生 > >第七章、Spring Boot MyBatis升級篇

第七章、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升級篇-註解[email protected]

@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/[email protected] 引數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升級

課時二十七、Spring Boot MyBatis升級篇-註解 緣起:在一節視訊中,有這麼一段留言:“會不會推出SpringBoot整合Mybaits配置檔案sqlMapConfig.xml搭配mapper.xml的視訊呢??? 看到有這個整合直接付款來看,結果是急速開發模

Spring Boot MyBatis升級-註解-動態SQL(if test)-方案二:@Provider(8)

指定 ins pro builder except uil test 就是 class 1)動態語言註解(2)@Provider使用思路(3)@SelectProvider小試牛刀(4)@SelectProvider初露鋒芒(5)@SelectProvider過關斬將(6)

【算法導論】快速排序

很好 補充 第七章 而是 合並 art 元素 一個 排序 快排的優勢: 1、期望為O(n lgn) 2、常數因子比較小 3、就地排序 4、在虛存環境很好工作 與合並排序一樣是分治思想,但是不是從中間截斷,而是通過partition過程實現的 每次選擇最後一個元素為q,然

Python字符編碼

編碼格式 點擊 這一 浪費 end 定性 支持 開始 can 第七章、Python字符編碼 一、定義 計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的英文、漢字等字符是二進制數轉換之後的結果。通俗的說,按照何種規則將字符存儲在計算機中,如‘a‘用什麽表示,稱為"

基本數據類型(tuple)

如果 error: error 刪除 位置 str bsp app ror 1.元組是有序的,一般寫元素的時候,推薦在最後加入逗號(,); 2.元組是可以叠代的; tuple_test=(10,20,30,["list","Jim","Mary",(123,"xuhong

spring cloud---feign+Hystrix熔斷器

熔斷器 雪崩效應 在微服務架構中通常會有多個服務層呼叫,基礎服務的故障可能會導致級聯故障,進而造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。服務雪崩效應是一種因“服務提供者”的不可用導致“服務消費者”的不可用,並將不可用逐漸放大的過程。 如果下圖所示:A作為服務提供者,B

spring cloud---熔斷監控Hystrix+Dashboard+Turbine+security

Hystrix+Dashboard+Turbine+security整合 Hystrix-dashboard是一款針對Hystrix進行實時監控的工具,通過Hystrix Dashboard我們可以在直觀地看到各Hystrix Command的請求響應時間, 請求成功率等資料。

SpringBoot | Spring boot 資料來源未配置,啟動異常

1、問題 在使Springboot自動生成的專案框架時如果選擇了資料來源,比如選擇了mysql依賴,生成專案之後,在沒有任何的配置時啟動會報一下異常,執行程式後,控制檯輸出錯誤日誌: 2018-12-04 14:00:46.890  WARN 6592 --- [ &n

【springboot】3Spring Boot+Mybatis

依賴配置 結合前面的內容,這裡我們要嵌入資料庫的操作,這裡以操作mysql為例整合Mybatis,首先需要在原來的基礎上新增以下依賴 <!-- mybatis依賴 --> <dependency> <groupId>org.my

Spring boot):Spring boot+ mybatis 多資料來源最簡解決方案

多資料來源一般解決哪些問題?主從模式或者業務比較複雜需要連線不同的分庫來支援業務。 直接上程式碼。 配置檔案 pom包依賴,該依賴的依賴。主要是資料庫這邊的配置: mybatis.config-locations=classpath:mybatis/mybati

Android群英傳學習——Android動畫機制與使用技巧

動畫能夠讓互動更加友好,特別是在提示、引導類的場景中,合理的使用動畫能讓使用者獲得更加愉悅的使用體驗。 學習本章,我們將瞭解到以下內容: ●Android檢視動畫 ●Android屬性動畫 ●Android動畫例項 一、Android View動畫框架

《鳥哥的Linux私房菜基礎》Linux 檔案與目錄管理

絕對路徑:『一定由根目弽 / 寫起』;相對路徑:『不是由 / 寫起』 特殊目錄有:., .., -, ~, ~account需要注意; 與目錄相關的指令有:cd, mkdir, rmdir, pwd 等重要指令; rmdir 僅能刪除空目錄,要刪除非空目錄需使用『 rm

四十Spring Boot 自定義攔截器

ram obj pre .config factor ati bean configure 邏輯 1.首先編寫攔截器代碼 package com.sarnath.interceptor; import javax.servlet.http.HttpServlet

OpenGL藍寶書:立體天空和紋理折射雙紋理(下)

ever oot 可行性 VR char 都是 pipeline 差異 pac 對照了藍寶書,才知道紅寶書的長處。 reflect函數的原理在紅寶書中有說明,僅僅有

《構建之法》 閱讀與思考

領導者 學會 如何解決 隨著 工程 什麽 清醒 處理 class 第四章:兩人合作 引文:身旁這個家夥老是問問題,他/她不會看書嗎?我都無法專心工作了。 如果軟件工程師連一對一的合作都做不好,不能有效地去影響同伴,讓

讀《構建之法》

span 指定 十分 鸚鵡 市場 utf 亂碼 修改 職業道德 第四章《兩人合作》 1.原文:“註釋(包括所有源代碼)應該只用ASCLL字符,不要使用中文和其他字符,否則會極大影響程序的可植性” 疑問:引擎根本不對空行和註釋進行解析,直接忽略掉,它們不參與計算代碼行數也不參

讀《構建之法》有感

author 基礎 忽略 旁觀者 才有 htm 心理 核心 選擇 書是我們永遠的朋友 它陪伴我們走過人生的春夏秋冬 在我們的生命中生根、發芽、枝繁葉茂 書是人類發展的錄像機 我們可以在其中看到前輩的足跡 書是知識的海洋 我願是一葉輕舟,載著理想之帆 在海

閱讀《構建之法》收獲

... 如果 spa exist 通用 類成員函數 根據 認識 ron 閱讀《構建之法》第四章、第十七章 閱讀這一章的時候,我意識到了很多以前寫程序沒有註意到的地方,以前寫程序就只知道能運行就好,根本不管自己寫的程序占多少內存,運行的時間,是否有優化的空間,寫代碼的時候也不

從.Net到Java學習——spring boot+mybatis+mysql

jar fig targe list pro ble TE png tween 環境:mysql5.7 新建mysql數據庫demo,然後執行如下sql腳本進行數據表創建和數據初始化: -- ---------------------------- -- Tabl

springCloud Spring Boot mybatis分布式微服務雲架構-docker-feign-hystrix-ribbon(

vid 目的 rul exec err eureka lis 負載均衡 分布式 簡介 在上一節中,我們討論了feign+hystrix在項目開發中,除了考慮正常的調用之外,負載均衡和故障轉移也是關註的重點,這也是feign + ribbon+hystrix的優勢所在,本節我