文章目錄
一、簡介
二、集成MP
-
創建測試表
CREATE DATABASE mp; USE mp; CREATE TABLE tbl_employee( id INT(11) PRIMARY KEY AUTO_INCREMENT, last_name VARCHAR(50), email VARCHAR(50), gender CHAR(1), age INT ); INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('tom','[email protected]',1,22); INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('jerry','[email protected]',0,25); INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('black','[email protected]',1,30); INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('white','[email protected]',0,35);
-
創建JavaBean
public class Employee{ private Integer id; private String lastName; private String email; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Employee{" + "id=" + id + ", lastName='" + lastName + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; } }
-
依賴配置
-
pom.xml配置
<dependencies> <!-- mybatis-plus會自動維護我們的mybatis以及mybatis-spring相關的依賴--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.9</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.10.RELEASE</version> </dependency> </dependencies>
-
加入mybatis全局配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> </configuration>
-
加入db.properties 連接配置信息
jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/mp jdbc.username = root jdbc.password = 123456
-
加入Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <!-- 加載配置屬性文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置SessionFactory --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="org.sy.library.entity.*"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- MyBatis 動態掃描 --> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.mp.mapper"/> </bean> <!-- 配置數據源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 事務管理器--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 基於註解的事務管理--> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/> </beans>
-
-
測試
-
測試spring-mybatis環境
public class TestMP { private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void testDataSource() throws SQLException { DataSource ds = ioc.getBean("dataSource",DataSource.class); System.out.println(ds); Connection connection = ds.getConnection(); System.out.println(connection); } }
-
-
集成MP
-
mybatis-plus的集成非常簡單,對於spring,我們僅僅需要把mybatis自帶的SessionFactoryBean替換爲MP自帶的MybatisSqlSessionFactoryBean即可(在配置文件中已直接更換)
-
三、入門
-
通用CRUD
-
實現方式
- 基於mybatis:
需要編寫EmployeeMapper接口,並手動編寫CRUD方法
提供EmployeeMapper.xml映射文件,並手動編寫每個方法對應的SQL語句 - 基於mybatis-plus:
只需要編寫EmployeeMapper接口,並實現BaseMapper接口,這就是使用MP
需要完成的所有操作,甚至不需要創建SQL映射文件
- 創建Mapper接口
public interface EmployeeMapper extends BaseMapper<Employee> { }
- 基於mybatis:
-
插入操作
-
測試
@Test public void testInsert(){ Employee employee = new Employee(); employee.setLastName("MP"); employee.setEmail("[email protected]"); employee.setGender(1); employee.setAge(22); Integer insert = employeeMapper.insert(employee); System.out.println(insert); }
出現異常:
org.mybatis.spring.MyBatisSystemException: nested exception isorg.apache.ibatis.reflection.ReflectionException: Could not setproperty ‘id’ of ‘class com.mp.beans.Employee’ with value ‘1274261141571284993’ Cause: java.lang.IllegalArgumentException: argument type mismatch
其原因是mybatis-plus在爲我們自動生成主鍵時出現錯誤,此時需要用到註解
再次運行該異常消失,但又出現了新異常
很明顯,字面意思就是找不到mp數據庫中employee表,我們的表名是tbl_employee,此時便用到了另一個註解
再次運行測試即可成功
-
MP全局配置策略
在application.xml可配置mybatis-plus全局配置策略<!-- MyBatisPlus 全局策略配置--> <bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- 2.3版本後默認值爲true,因此不寫也可--> <property name="dbColumnUnderline" value="true"></property> <!--全局的主鍵策略--> <!-- 相當於@TableId(value = "id",type = IdType.AUTO)--> <property name="idType" value="0"></property> <!-- 全局的表前綴策略配置--> <!-- 相當於@TableName(value = "tbl_+實體類名(小寫)")--> <property name="tablePrefix" value="tbl_"></property> </bean>
將其注入到SQLSessionFactoryBean中
將Employee中id上的@TableId
與@TableName
註解註釋掉後,測試插入依然可以還有一點需要注意,在mybatis中如果需要獲取返回插入數據的主鍵值,還需要在mapper.xml中進行屬性配置,而mybatis-plus則不需要任何配置,他會自動返回插入數據的主鍵值;
在測試插入方法加上兩行代碼;獲取返回的Id值
-
測試insertAllColumn方法(3.0版本後棄用,瞭解即可)
insert方法有一個小問題,就是在插入的時候,他會掃描那些屬性賦了值,在插入的時候只會對你賦值的屬性進行操作,insertAllColumn解決的就是這一問題,無論你賦沒賦值,他都會對所有屬性進行操作Employee employee = new Employee(); employee.setLastName("MP"); employee.setEmail("[email protected]"); employeeMapper.insert(employee); //當使用insert方法插入,插入語句如下 insert into tbl_employee(last_name,email) values('MP','[email protected]'); //當使用insertAllColumn方法插入,插入語句如下 insert into tbl_employee(last_name,email,gender,age) values('MP','[email protected]',null,null); 注意:二者只在SQL語句上有區別,插入結果是沒有區別的
-
-
更新操作
@Test public void testUpdate(){ Employee employee = new Employee(); employee.setId(5); employee.setLastName("QQQ"); employee.setEmail("[email protected]"); employee.setGender(3); employee.setAge(25); Integer update = employeeMapper.updateById(employee); System.out.println(update); }
-
查詢操作
@Test public void testSelect(){ //1.通過Id查詢 Employee employee = employeeMapper.selectById(1); System.out.println(employee); //2.通過多個列查詢;只能查詢一條記錄,有多條記錄會報錯 Employee employee2 = new Employee(); employee2.setId(5); employee2.setLastName("QQQ"); Employee employee1 = employeeMapper.selectOne(employee2); System.out.println(employee1); //3.通過多個id查詢 List<Integer> idList = new ArrayList<>(); idList.add(1); idList.add(2); idList.add(3); List<Employee> employees = employeeMapper.selectBatchIds(idList); System.out.println(Arrays.asList(employees)); //4.通過Map封裝條件查詢 Map<String,Object> map = new HashMap<>(); map.put("last_name","MP"); map.put("gender",1); List<Employee> employees1 = employeeMapper.selectByMap(map); System.out.println(Arrays.asList(employees1)); //5.分頁查詢:查詢第3頁,每頁2條記錄 List<Employee> employees2 = employeeMapper.selectPage(new Page<>(3, 2), null); System.out.println(Arrays.asList(employees2)); }
-
刪除操作
@Test public void testDelete(){ //1.根據Id刪除 Integer integer = employeeMapper.deleteById(10); System.out.println(integer); //2.根據多個條件刪除 Map<String,Object> map = new HashMap<>(); map.put("id",5); map.put("last_name","QQQ"); Integer integer1 = employeeMapper.deleteByMap(map); System.out.println(integer1); //3.刪除多個 List<Integer> idList = new ArrayList<>(); idList.add(6); idList.add(7); idList.add(8); Integer integer3 = employeeMapper.deleteBatchIds(idList); System.out.println(integer3); }
-
MP啓動注入SQL原理分析
- 問題:xxxMapper 繼承了BaseMapper 中提供了通用的CRUD方法,方法來源於 BaseMapper,有方法就必須有SQL,一位Mybatis最終還是需要通過SQL語句操作數據
MP在啓動時就會挨個分析xxxMapper中的方法,並且將對應的SQL語句處理好,保存到configuration對象中的mappedStatements中
本質:
- 問題:xxxMapper 繼承了BaseMapper 中提供了通用的CRUD方法,方法來源於 BaseMapper,有方法就必須有SQL,一位Mybatis最終還是需要通過SQL語句操作數據
-
小結
- 以上是基本的CRUD操作,我們僅需要繼承一個BaseMapper即可實現大部分表單CRUD操作。BaseMapper提供了多達17個方法供我們使用,可以極其方便的實現單一、批量、分頁等操作。極大地減少開發負擔。
- 當我們有一個需求,需要在分頁查詢Employee表中,年齡在18~52之間且性別爲男性,姓名爲xx的所有用戶,該如何實現?
- Mybatis:需要在SQL映射文件中編寫帶條件查詢的SQL且基於PageHelper插件或其他完成分頁
- Mybatis-Plus:依舊不需編寫SQL語句,MP提供了功能強大的條件構造器 EntityWrapper;
-
四、條件構造器 EntityWrapper
注意:(3.0之後拆分爲AbstractWrapper、QueryWrapper、UpdateWrapper以及使用 Wrapper 自定義SQL,詳情可查官網)
-
簡介
- Mybatis-Plus通過EntityWrapper(簡稱EW,MP封裝的一個查詢條件構造器)或者Condition(與EW類似)來讓用戶自由的構建查詢條件,簡單便捷,沒有額外的負擔,能夠有效提高開發效率
- 實體包裝器,主要用於處理SQL拼接,排序,實體參數查詢等
- 注意:使用的是數據庫字段,不是Java屬性
- 條件參數說明
-
測試
-
分頁查詢
@Test public void testEntityWrapperSelect(){ //需要在分頁查詢Employee表中,年齡在18~50之間且性別爲男性,姓名爲MP的所有用戶 List<Employee> age = employeeMapper.selectPage(new Page<Employee>(1, 2), new EntityWrapper<Employee>() .between("age", 18, 50) .eq("gender",1) .eq("last_name","MP")); System.out.println(Arrays.asList(age)); }
-
帶條件查詢
@Test public void testEntityWrapperSelect2(){ //查詢在tbl_employee表中,性別爲女且名字中帶有“e”或者郵箱中帶有“o” List<Employee> employees = employeeMapper.selectList(new EntityWrapper<Employee>() .eq("gender", 0) .like("last_name", "e") //.or() // WHERE (gender = ? AND last_name LIKE ? OR email LIKE ?) .orNew() //WHERE (gender = ? AND last_name LIKE ?) OR (email LIKE ?) .like("email", "o")); System.out.println(Arrays.asList(employees)); }
@Test public void testEntityWrapperSelect3(){ Employee employee = new Employee(); employee.setLastName("www"); employee.setEmail("[email protected]"); employee.setAge(29); Integer update = employeeMapper.update(employee, new EntityWrapper<Employee>().eq("last_name", "MP1")); System.out.println(update); }
-
刪除操作
@Test public void testEntityWrapperSelect4(){ Integer delete = employeeMapper.delete(new EntityWrapper<Employee>().eq("last_name", "www")); System.out.println(delete); }
-
五、ActiveRecord(活動記錄)
-
簡介
ActiveRecord(活動記錄),一種領域模型模式,特點是一個模型類對應關係型數據庫中的一個表,而模型類的一個實例對應表中的一行記錄
-
如何使用AR模式
僅僅需要讓實體類繼承Model類且實現主鍵指定方法,即可開始AR之旅
-
AR基本CRUD
-
插入操作
@Test public void testARInsert(){ Employee employee = new Employee(); employee.setLastName("蒼井空"); employee.setEmail("[email protected]"); employee.setAge(35); employee.setGender(0); boolean insert = employee.insert(); System.out.println(insert); }
-
修改操作
@Test public void testARInsert(){ Employee employee = new Employee(); employee.setLastName("蒼井空"); employee.setEmail("[email protected]"); employee.setAge(35); employee.setGender(0); boolean insert = employee.insert(); System.out.println(insert); }
-
查詢操作
@Test public void testARSelect(){ //1.根據Id查詢 Employee employee = new Employee(); Employee employee1 = employee.selectById(15); System.out.println(employee1); //2.查詢全部 List<Employee> employees = employee.selectAll(); System.out.println(Arrays.asList(employees)); //3.模糊查詢 List<Employee> employees1 = employee.selectList(new EntityWrapper<Employee>().like("last_name", "M")); System.out.println(Arrays.asList(employees1)); //4.查個數 int gender = employee.selectCount(new EntityWrapper<Employee>().eq("gender", 0)); System.out.println(gender); }
-
刪除操作
@Test public void testARDelete(){ Employee employee = new Employee(); boolean b = employee.deleteById(15); System.out.println(b); boolean delete = employee.delete(new EntityWrapper<Employee>().eq("last_name", "MP")); System.out.println(delete); }
-
分頁複雜操作
@Test public void testARSelectPage(){ List<Employee> employees = employeeMapper.selectPage(new Page<Employee>(2, 1), new EntityWrapper<Employee>().like("email", "e")); System.out.println(employees); }
-
-
AR小結
- AR模式提供了一種更加便捷的方式實現CRUD操作,其本質還是調用的Mybatis對應的方法。
- Mybatis-Plus爲我們提供了強大的代碼生成器,可以快速生成各類代碼,真正做到即開即用
六、代碼生成器
-
簡介
- MP提供了大量的自定義設置,生成的代碼完全能夠滿足各種類型的需求
- 表及字段命名策略選擇
- 在MP中,我們建議數據庫表名和表字段名採用駝峯命名方式,如果採用下劃線命名方式,請開啓全局下劃線開關,如果表名字段命名方式不一致要註解指定,建議保持一致
- 這麼做的原因是爲了避免在對應實體類時產生的性能損耗,這樣字段不用做映射就能直接和實體類對應。當然如果項目裏不用考慮這點性能損耗,那麼採用下劃線也是沒問題的,只需在生成代碼時配置dbColumnUnderline屬性就可以。
- MP的代碼生成器與Mybatis MBG代碼生成器對比:
- MP的代碼生成器都是基於Java代碼來生成的,MBG是基於xml文件進行代碼生成
- Mybatis的代碼生成器可生成:實體類、Mapper接口、Mapper映射文件
MP的代碼生成器可生成:實體類(可以選擇是否支持AR)、Mapper接口、Mapper映射文件、Service層、Controller層。
-
代碼生成器依賴
<!-- MP的代碼生成器默認使用的是Apache的Velocity模板--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.1</version> </dependency> <!-- 加入slf4j,查看日誌輸出信息--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency>
-
MP代碼生成器實例代碼(詳細可查官網)
/** * 代碼生成器 */ @Test public void test(){ //1.全局配置 GlobalConfig config = new GlobalConfig(); config.setActiveRecord(true) //是否支持AR模式 .setAuthor("東方老贏")//作者 .setOutputDir("F:\\test")//生成路徑 .setFileOverride(true)//文件覆蓋 .setIdType(IdType.AUTO)//主鍵策略 .setServiceName("%sService")//設置生成的service接口的名字的首字母(默認爲I) .setBaseResultMap(true)//XML ResultMap .setBaseColumnList(true);//XML columList //2.數據源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setDbType(DbType.MYSQL)//設置數據庫類型 .setDriverName("com.mysql.jdbc.Driver") .setUsername("root") .setPassword("123456") .setUrl("jdbc:mysql://127.0.0.1:3306/mp"); //3.策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setCapitalMode(true)// 全局大寫命名 ORACLE 注意 .setDbColumnUnderline(true)//指定表名、字段名是否使用下劃線 .setTablePrefix("tbl_")// 此處可以修改爲您的表前綴 .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略 .setInclude("tbl_employee" ); // 需要生成的表 //4.包名策略配置 PackageConfig pc = new PackageConfig(); pc.setParent("com.mp.velocity") .setMapper("mapper") .setService("service") .setController("controller") .setEntity("beans") .setXml("mapper"); //5.整合配置 AutoGenerator ag = new AutoGenerator(); ag.setGlobalConfig(config); ag.setStrategy(strategy); ag.setDataSource(dsc); ag.setPackageInfo(pc); //執行 ag.execute(); }
運行測試成功後會自動打開文件位置
七、自定義全局操作
-
簡介
- 根據Mybatis-Plus的AutoSqlInjector 可以自定義各種你想要的SQL,注入到全局中,相當於自定義Mybatis-Plus自動注入的方法
- 之前需要在xml中進行配置的SQL語句,現在通過擴展AutoSqlInjector 在加載Mybatis環境時就注入
-
AutoSqlInjector
- 在Mapper接口中定義相關的CRUD方法
- 在擴展AutoSqlInjector inject方法,實現Mapper接口中方法要注入的SQL
- 在MP全局策略中,配置自定義注入器
-
自定義注入器的應用值邏輯刪除
在Mapper接口中定義相關的CRUD方法
public interface EmployeeMapper extends BaseMapper<Employee> { int deleteAll(); }
在擴展AutoSqlInjector inject方法,實現Mapper接口中方法要注入的SQL
public class MySqlInjector extends AutoSqlInjector { @Override public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) { /* 添加一個自定義方法 */ deleteAllUser(mapperClass, modelClass, table); } public void deleteAllUser(Class<?> mapperClass, Class<?> modelClass, TableInfo table) { /* 執行 SQL ,動態 SQL 參考類 SqlMethod */ String sql = "delete from " + table.getTableName(); /* mapper 接口方法名一致 */ String method = "deleteAll"; SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); this.addMappedStatement(mapperClass, method, sqlSource, SqlCommandType.DELETE, Integer.class); } }
在MP全局策略中,配置自定義注入器
<!-- 定義 MP 全局策略,安裝集成文檔部分結合 --> <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> ..... <!-- 自定義注入 deleteAll 方法 --> <property name="sqlInjector" ref="mySqlInjector" /> </bean> <!-- 自定義注入器 --> <bean id="mySqlInjector" class="com.baomidou.test.MySqlInjector" />
八、公共字段自動填充
-
實現元對象處理器接口: com.baomidou.mybatisplus.mapper.IMetaObjectHandler
-
註解填充字段
@TableField(.. fill = FieldFill.INSERT)
生成器策略部分也可以配置!public class User { // 注意!這裏需要標記爲填充字段 @TableField(.. fill = FieldFill.INSERT) private String fillField; .... }
-
自定義實現類 MyMetaObjectHandler
/** 自定義填充公共 name 字段 */ public class MyMetaObjectHandler extends MetaObjectHandler { /** * 測試 user 表 name 字段爲空自動填充 */ public void insertFill(MetaObject metaObject) { // 更多查看源碼測試用例 System.out.println("*************************"); System.out.println("insert fill"); System.out.println("*************************"); // 測試下劃線 Object testType = getFieldValByName("testType", metaObject);//mybatis-plus版本2.0.9+ System.out.println("testType=" + testType); if (testType == null) { setFieldValByName("testType", 3, metaObject);//mybatis-plus版本2.0.9+ } } @Override public void updateFill(MetaObject metaObject) { //更新填充 System.out.println("*************************"); System.out.println("update fill"); System.out.println("*************************"); //mybatis-plus版本2.0.9+ setFieldValByName("lastUpdatedDt", new Timestamp(System.currentTimeMillis()), metaObject); } }
-
spring 啓動注入 MyMetaObjectHandler 配置
<!-- MyBatis SqlSessionFactoryBean 配置 --> <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <property name="globalConfig" ref="globalConfig"></property> </bean> <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- 公共字段填充處理器 --> <property name="metaObjectHandler" ref="myMetaObjectHandler" /> </bean> <!-- 自定義處理器 --> <bean id="myMetaObjectHandler" class="com.baomidou.test.MyMetaObjectHandler" />