說到DAO不得不提一個開發名詞"三層架構",所謂的三層架構是什麼呢?簡單的能夠歸納爲數據訪問層,業務邏輯層,界面層(又稱表現層).html
這也是咱們Java開發經常使用的手段,常常有人將三層架構和mvc模式混淆,在我看來,三層架構就是三層架構,mvc只是三層架構中的表現層中的架構,至關於在一個比較大的層面,往裏面在細分,mvc細分,可分爲模型,視圖,控制器,在這裏模型一般指數據,也能夠叫JavaBean,而視圖的話,這個視圖就是展現給用戶看的,一般用於視圖的模板能夠爲jsp,freemarker,beetl,velocity或者是springboot推薦使用的thymeleaf等,固然也能夠是純html,不過須要ajax交互獲取後臺的數據。控制器的話,讓人不由想起了servlet,控制器的做用就至關於servlet的做用,就是對http請求進行處理。java
mvc模式也是如今流行的一種軟件設計模式。面試
三層架構能夠用來作什麼呢?答能夠作不少,最大的做用,用一句官方的話,"高內聚,低耦合",軟件開發中的大忌就是高耦合,內聚的意思我不是十分明白,不過耦合仍是很讓人理解的,耦合度高就是你改完這個代碼,另外的也要改,再另外的又要改,對於互聯網項目,需求變動是常常的,耦合度高的話,開發項目的效率將會很是低下。ajax
我這我的比較喜歡開場博文說說行內話,如今開始講講咱們的mybatis plus的dao吧!spring
首先仍是那句話,貼源碼分析講解sql
/** * Copyright (c) 2011-2020, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.mapper; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.session.RowBounds; /** * <p> * Mapper 繼承該接口後,無需編寫 mapper.xml 文件,便可得到CRUD功能 * </p> * <p> * 這個 Mapper 支持 id 泛型 * </p> * * @author hubin * @Date 2016-01-23 */ public interface BaseMapper<T> { /** * <p> * 插入一條記錄 * </p> * * @param entity 實體對象 * @return int */ Integer insert(T entity); /** * <p> * 插入一條記錄 * </p> * * @param entity 實體對象 * @return int */ Integer insertAllColumn(T entity); /** * <p> * 根據 ID 刪除 * </p> * * @param id 主鍵ID * @return int */ Integer deleteById(Serializable id); /** * <p> * 根據 columnMap 條件,刪除記錄 * </p> * * @param columnMap 表字段 map 對象 * @return int */ Integer deleteByMap(@Param("cm") Map<String, Object> columnMap); /** * <p> * 根據 entity 條件,刪除記錄 * </p> * * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return int */ Integer delete(@Param("ew") Wrapper<T> wrapper); /** * <p> * 刪除(根據ID 批量刪除) * </p> * * @param idList 主鍵ID列表 * @return int */ Integer deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList); /** * <p> * 根據 ID 修改 * </p> * * @param entity 實體對象 * @return int */ Integer updateById(@Param("et") T entity); /** * <p> * 根據 ID 修改 * </p> * * @param entity 實體對象 * @return int */ Integer updateAllColumnById(@Param("et") T entity); /** * <p> * 根據 whereEntity 條件,更新記錄 * </p> * * @param entity 實體對象 * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return */ Integer update(@Param("et") T entity, @Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 ID 查詢 * </p> * * @param id 主鍵ID * @return T */ T selectById(Serializable id); /** * <p> * 查詢(根據ID 批量查詢) * </p> * * @param idList 主鍵ID列表 * @return List<T> */ List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList); /** * <p> * 查詢(根據 columnMap 條件) * </p> * * @param columnMap 表字段 map 對象 * @return List<T> */ List<T> selectByMap(@Param("cm") Map<String, Object> columnMap); /** * <p> * 根據 entity 條件,查詢一條記錄 * </p> * * @param entity 實體對象 * @return T */ T selectOne(@Param("ew") T entity); /** * <p> * 根據 Wrapper 條件,查詢總記錄數 * </p> * * @param wrapper 實體對象 * @return int */ Integer selectCount(@Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 entity 條件,查詢所有記錄 * </p> * * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return List<T> */ List<T> selectList(@Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 Wrapper 條件,查詢所有記錄 * </p> * * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return List<T> */ List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 Wrapper 條件,查詢所有記錄 * 注意: 只返回第一個字段的值 * </p> * * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return List<Object> */ List<Object> selectObjs(@Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 entity 條件,查詢所有記錄(並翻頁) * </p> * * @param rowBounds 分頁查詢條件(能夠爲 RowBounds.DEFAULT) * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return List<T> */ List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper); /** * <p> * 根據 Wrapper 條件,查詢所有記錄(並翻頁) * </p> * * @param rowBounds 分頁查詢條件(能夠爲 RowBounds.DEFAULT) * @param wrapper 實體對象封裝操做類 * @return List<Map<String, Object>> */ List<Map<String, Object>> selectMapsPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper); }
在Java中有一句經典的話,一個類只能繼承一個類,但能夠實現多個接口,一樣一個接口能夠繼承多個接口數據庫
在此不得不提到一個常見的面試考題:express
接口和抽象類的區別:apache
相同點:設計模式
(1)接口和抽象類中都存在抽象方法(抽象方法,就是隻聲明但還沒有實現的方法稱爲抽象方法),固然一個前提,該抽象類必需要用abstract修飾符修飾,因此咱們能夠總結它一個共同點即抽象方法。
(2)不能實例化
不一樣點:
接口:
(1)接口中全部的方法必須是抽象方法;
(2)接口能夠多繼承(可一個接口繼承多個接口,上述的mybatis plus就是基於這個),一樣一個接口也能夠實現多個接口,這個例子比比皆是;
(3)接口不能實例化
抽象類:
(1)抽象類中能夠存在非抽象方法,同時也能夠存在抽象方法;
(2)抽象類只能單繼承(因此說一個類只能繼承一個父類,因此說java是單根繼承的,也能夠說它是多繼承,由於接口具備多繼承性質,經過實現多個接口來完成的)
(3)抽象類中能夠有靜態屬性,也可有非靜態屬性;
下面附我博客的UserDao繼承上述BaseMapper接口
package com.blog.dao; import java.io.Serializable; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.blog.entity.UserEntity; public interface UserDao extends BaseMapper<UserEntity> { }
經過繼承,個人UserDao具備增,刪,改,查等多個方法;經過繼承,我再也不須要像原始mybatis那樣,每寫一個方法須要在xml文件進行相應的配置,不然會報異常
看BaseMapper源碼,再結合個人UserDao,發現繼承是個很好的東西。假如我有一百個dao,我只需繼承BaseMapper,就有了對應的一系列增刪改查。那麼對於開發效率是有多麼大的提升啊!
繼承思想是個好玩意!好比在js中,日期函數,經常使用的郵件,手機號,數字等表單校驗,全局獲取cookie,清除cookie等我能夠將其抽象爲一個js文件,而後引用到其餘html中,其餘html就能夠用了。這體現了複用思想,同時也間接性反映了繼承。
再貼貼Service代碼,也是同樣的原理
package com.blog.service; import java.util.Map; import com.baomidou.mybatisplus.service.IService; import com.blog.entity.UserEntity; import com.blog.utils.PageUtils; public interface UserService extends IService<UserEntity> { }
IService源碼:
/** * Copyright (c) 2011-2016, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.service; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import com.baomidou.mybatisplus.mapper.Wrapper; import com.baomidou.mybatisplus.plugins.Page; /** * <p> * 頂級 Service * </p> * * @author hubin * @Date 2016-04-20 */ public interface IService<T> { /** * <p> * 插入一條記錄(選擇字段,策略插入) * </p> * * @param entity 實體對象 * @return boolean */ boolean insert(T entity); /** * <p> * 插入一條記錄(所有字段) * </p> * * @param entity 實體對象 * @return boolean */ boolean insertAllColumn(T entity); /** * <p> * 插入(批量),該方法不適合 Oracle * </p> * * @param entityList 實體對象列表 * @return boolean */ boolean insertBatch(List<T> entityList); /** * <p> * 插入(批量) * </p> * * @param entityList 實體對象列表 * @param batchSize 插入批次數量 * @return boolean */ boolean insertBatch(List<T> entityList, int batchSize); /** * <p> * 批量修改插入 * </p> * * @param entityList 實體對象列表 * @return boolean */ boolean insertOrUpdateBatch(List<T> entityList); /** * <p> * 批量修改插入 * </p> * * @param entityList 實體對象列表 * @param batchSize * @return boolean */ boolean insertOrUpdateBatch(List<T> entityList, int batchSize); /** * <p> * 批量修改或插入所有字段 * </p> * * @param entityList 實體對象列表 * @return boolean */ boolean insertOrUpdateAllColumnBatch(List<T> entityList); /** * 批量修改或插入所有字段 * * @param entityList 實體對象列表 * @param batchSize * @return boolean */ boolean insertOrUpdateAllColumnBatch(List<T> entityList, int batchSize); /** * <p> * 根據 ID 刪除 * </p> * * @param id 主鍵ID * @return boolean */ boolean deleteById(Serializable id); /** * <p> * 根據 columnMap 條件,刪除記錄 * </p> * * @param columnMap 表字段 map 對象 * @return boolean */ boolean deleteByMap(Map<String, Object> columnMap); /** * <p> * 根據 entity 條件,刪除記錄 * </p> * * @param wrapper 實體包裝類 {@link Wrapper} * @return boolean */ boolean delete(Wrapper<T> wrapper); /** * <p> * 刪除(根據ID 批量刪除) * </p> * * @param idList 主鍵ID列表 * @return boolean */ boolean deleteBatchIds(Collection<? extends Serializable> idList); /** * <p> * 根據 ID 選擇修改 * </p> * * @param entity 實體對象 * @return boolean */ boolean updateById(T entity); /** * <p> * 根據 ID 修改所有字段 * </p> * * @param entity 實體對象 * @return boolean */ boolean updateAllColumnById(T entity); /** * <p> * 根據 whereEntity 條件,更新記錄 * </p> * * @param entity 實體對象 * @param wrapper 實體包裝類 {@link Wrapper} * @return boolean */ boolean update(T entity, Wrapper<T> wrapper); /** * <p> * 根據ID 批量更新 * </p> * * @param entityList 實體對象列表 * @return boolean */ boolean updateBatchById(List<T> entityList); /** * <p> * 根據ID 批量更新 * </p> * * @param entityList 實體對象列表 * @param batchSize 更新批次數量 * @return boolean */ boolean updateBatchById(List<T> entityList, int batchSize); /** * <p> * 根據ID 批量更新所有字段 * </p> * * @param entityList 實體對象列表 * @return boolean */ boolean updateAllColumnBatchById(List<T> entityList); /** * <p> * 根據ID 批量更新所有字段 * </p> * * @param entityList 實體對象列表 * @param batchSize 更新批次數量 * @return boolean */ boolean updateAllColumnBatchById(List<T> entityList, int batchSize); /** * <p> * TableId 註解存在更新記錄,否插入一條記錄 * </p> * * @param entity 實體對象 * @return boolean */ boolean insertOrUpdate(T entity); /** * 插入或修改一條記錄的所有字段 * * @param entity 實體對象 * @return boolean */ boolean insertOrUpdateAllColumn(T entity); /** * <p> * 根據 ID 查詢 * </p> * * @param id 主鍵ID * @return T */ T selectById(Serializable id); /** * <p> * 查詢(根據ID 批量查詢) * </p> * * @param idList 主鍵ID列表 * @return List<T> */ List<T> selectBatchIds(Collection<? extends Serializable> idList); /** * <p> * 查詢(根據 columnMap 條件) * </p> * * @param columnMap 表字段 map 對象 * @return List<T> */ List<T> selectByMap(Map<String, Object> columnMap); /** * <p> * 根據 Wrapper,查詢一條記錄 * </p> * * @param wrapper 實體對象 * @return T */ T selectOne(Wrapper<T> wrapper); /** * <p> * 根據 Wrapper,查詢一條記錄 * </p> * * @param wrapper {@link Wrapper} * @return Map<String,Object> */ Map<String, Object> selectMap(Wrapper<T> wrapper); /** * <p> * 根據 Wrapper,查詢一條記錄 * </p> * * @param wrapper {@link Wrapper} * @return Object */ Object selectObj(Wrapper<T> wrapper); /** * <p> * 根據 Wrapper 條件,查詢總記錄數 * </p> * * @param wrapper 實體對象 * @return int */ int selectCount(Wrapper<T> wrapper); /** * <p> * 查詢列表 * </p> * * @param wrapper 實體包裝類 {@link Wrapper} * @return */ List<T> selectList(Wrapper<T> wrapper); /** * <p> * 翻頁查詢 * </p> * * @param page 翻頁對象 * @return */ Page<T> selectPage(Page<T> page); /** * <p> * 查詢列表 * </p> * * @param wrapper {@link Wrapper} * @return */ List<Map<String, Object>> selectMaps(Wrapper<T> wrapper); /** * <p> * 根據 Wrapper 條件,查詢所有記錄 * </p> * * @param wrapper 實體對象封裝操做類(能夠爲 null) * @return List<Object> */ List<Object> selectObjs(Wrapper<T> wrapper); /** * <p> * 翻頁查詢 * </p> * * @param page 翻頁對象 * @param wrapper {@link Wrapper} * @return */ @SuppressWarnings("rawtypes") Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper); /** * <p> * 翻頁查詢 * </p> * * @param page 翻頁對象 * @param wrapper 實體包裝類 {@link Wrapper} * @return */ Page<T> selectPage(Page<T> page, Wrapper<T> wrapper); }
其實和Dao也是同樣的
再貼貼Service實現類相關代碼:
package com.blog.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.blog.dao.UserDao; import com.blog.entity.UserEntity; import com.blog.service.UserService; @Service("userService") public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService { }
ServiceImpl源碼:
/** * Copyright (c) 2011-2016, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.service.impl; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.ibatis.binding.MapperMethod; import org.apache.ibatis.session.SqlSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.entity.TableInfo; import com.baomidou.mybatisplus.enums.SqlMethod; import com.baomidou.mybatisplus.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.baomidou.mybatisplus.mapper.Condition; import com.baomidou.mybatisplus.mapper.SqlHelper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.baomidou.mybatisplus.plugins.Page; import com.baomidou.mybatisplus.service.IService; import com.baomidou.mybatisplus.toolkit.CollectionUtils; import com.baomidou.mybatisplus.toolkit.MapUtils; import com.baomidou.mybatisplus.toolkit.ReflectionKit; import com.baomidou.mybatisplus.toolkit.StringUtils; import com.baomidou.mybatisplus.toolkit.TableInfoHelper; /** * <p> * IService 實現類( 泛型:M 是 mapper 對象,T 是實體 , PK 是主鍵泛型 ) * </p> * * @author hubin * @Date 2016-04-20 */ public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> { @Autowired protected M baseMapper; /** * <p> * 判斷數據庫操做是否成功 * </p> * <p> * 注意!! 該方法爲 Integer 判斷,不可傳入 int 基本類型 * </p> * * @param result 數據庫操做返回影響條數 * @return boolean */ protected static boolean retBool(Integer result) { return SqlHelper.retBool(result); } @SuppressWarnings("unchecked") protected Class<T> currentModelClass() { return ReflectionKit.getSuperClassGenricType(getClass(), 1); } /** * <p> * 批量操做 SqlSession * </p> */ protected SqlSession sqlSessionBatch() { return SqlHelper.sqlSessionBatch(currentModelClass()); } /** * 獲取SqlStatement * * @param sqlMethod * @return */ protected String sqlStatement(SqlMethod sqlMethod) { return SqlHelper.table(currentModelClass()).getSqlStatement(sqlMethod.getMethod()); } @Transactional(rollbackFor = Exception.class) @Override public boolean insert(T entity) { return retBool(baseMapper.insert(entity)); } @Transactional(rollbackFor = Exception.class) @Override public boolean insertAllColumn(T entity) { return retBool(baseMapper.insertAllColumn(entity)); } @Transactional(rollbackFor = Exception.class) @Override public boolean insertBatch(List<T> entityList) { return insertBatch(entityList, 30); } /** * 批量插入 * * @param entityList * @param batchSize * @return */ @Transactional(rollbackFor = Exception.class) @Override public boolean insertBatch(List<T> entityList, int batchSize) { if (CollectionUtils.isEmpty(entityList)) { throw new IllegalArgumentException("Error: entityList must not be empty"); } try (SqlSession batchSqlSession = sqlSessionBatch()) { int size = entityList.size(); String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE); for (int i = 0; i < size; i++) { batchSqlSession.insert(sqlStatement, entityList.get(i)); if (i >= 1 && i % batchSize == 0) { batchSqlSession.flushStatements(); } } batchSqlSession.flushStatements(); } catch (Throwable e) { throw new MybatisPlusException("Error: Cannot execute insertBatch Method. Cause", e); } return true; } /** * <p> * TableId 註解存在更新記錄,否插入一條記錄 * </p> * * @param entity 實體對象 * @return boolean */ @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdate(T entity) { if (null != entity) { Class<?> cls = entity.getClass(); TableInfo tableInfo = TableInfoHelper.getTableInfo(cls); if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) { Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty()); if (StringUtils.checkValNull(idVal)) { return insert(entity); } else { /* * 更新成功直接返回,失敗執行插入邏輯 */ return updateById(entity) || insert(entity); } } else { throw new MybatisPlusException("Error: Can not execute. Could not find @TableId."); } } return false; } @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdateAllColumn(T entity) { if (null != entity) { Class<?> cls = entity.getClass(); TableInfo tableInfo = TableInfoHelper.getTableInfo(cls); if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) { Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty()); if (StringUtils.checkValNull(idVal)) { return insertAllColumn(entity); } else { /* * 更新成功直接返回,失敗執行插入邏輯 */ return updateAllColumnById(entity) || insertAllColumn(entity); } } else { throw new MybatisPlusException("Error: Can not execute. Could not find @TableId."); } } return false; } @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdateBatch(List<T> entityList) { return insertOrUpdateBatch(entityList, 30); } @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdateBatch(List<T> entityList, int batchSize) { return insertOrUpdateBatch(entityList, batchSize, true); } @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdateAllColumnBatch(List<T> entityList) { return insertOrUpdateBatch(entityList, 30, false); } @Transactional(rollbackFor = Exception.class) @Override public boolean insertOrUpdateAllColumnBatch(List<T> entityList, int batchSize) { return insertOrUpdateBatch(entityList, batchSize, false); } /** * 批量插入修改 * * @param entityList 實體對象列表 * @param batchSize 批量刷新個數 * @param selective 是否濾掉空字段 * @return boolean */ private boolean insertOrUpdateBatch(List<T> entityList, int batchSize, boolean selective) { if (CollectionUtils.isEmpty(entityList)) { throw new IllegalArgumentException("Error: entityList must not be empty"); } try (SqlSession batchSqlSession = sqlSessionBatch()) { int size = entityList.size(); for (int i = 0; i < size; i++) { if (selective) { insertOrUpdate(entityList.get(i)); } else { insertOrUpdateAllColumn(entityList.get(i)); } if (i >= 1 && i % batchSize == 0) { batchSqlSession.flushStatements(); } } batchSqlSession.flushStatements(); } catch (Throwable e) { throw new MybatisPlusException("Error: Cannot execute insertOrUpdateBatch Method. Cause", e); } return true; } @Transactional(rollbackFor = Exception.class) @Override public boolean deleteById(Serializable id) { return SqlHelper.delBool(baseMapper.deleteById(id)); } @Transactional(rollbackFor = Exception.class) @Override public boolean deleteByMap(Map<String, Object> columnMap) { if (MapUtils.isEmpty(columnMap)) { throw new MybatisPlusException("deleteByMap columnMap is empty."); } return SqlHelper.delBool(baseMapper.deleteByMap(columnMap)); } @Transactional(rollbackFor = Exception.class) @Override public boolean delete(Wrapper<T> wrapper) { return SqlHelper.delBool(baseMapper.delete(wrapper)); } @Transactional(rollbackFor = Exception.class) @Override public boolean deleteBatchIds(Collection<? extends Serializable> idList) { return SqlHelper.delBool(baseMapper.deleteBatchIds(idList)); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateById(T entity) { return retBool(baseMapper.updateById(entity)); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateAllColumnById(T entity) { return retBool(baseMapper.updateAllColumnById(entity)); } @Transactional(rollbackFor = Exception.class) @Override public boolean update(T entity, Wrapper<T> wrapper) { return retBool(baseMapper.update(entity, wrapper)); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateBatchById(List<T> entityList) { return updateBatchById(entityList, 30); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateBatchById(List<T> entityList, int batchSize) { return updateBatchById(entityList, batchSize, true); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateAllColumnBatchById(List<T> entityList) { return updateAllColumnBatchById(entityList, 30); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateAllColumnBatchById(List<T> entityList, int batchSize) { return updateBatchById(entityList, batchSize, false); } /** * 根據主鍵ID進行批量修改 * * @param entityList 實體對象列表 * @param batchSize 批量刷新個數 * @param selective 是否濾掉空字段 * @return boolean */ private boolean updateBatchById(List<T> entityList, int batchSize, boolean selective) { if (CollectionUtils.isEmpty(entityList)) { throw new IllegalArgumentException("Error: entityList must not be empty"); } try (SqlSession batchSqlSession = sqlSessionBatch()) { int size = entityList.size(); SqlMethod sqlMethod = selective ? SqlMethod.UPDATE_BY_ID : SqlMethod.UPDATE_ALL_COLUMN_BY_ID; String sqlStatement = sqlStatement(sqlMethod); for (int i = 0; i < size; i++) { MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>(); param.put("et", entityList.get(i)); batchSqlSession.update(sqlStatement, param); if (i >= 1 && i % batchSize == 0) { batchSqlSession.flushStatements(); } } batchSqlSession.flushStatements(); } catch (Throwable e) { throw new MybatisPlusException("Error: Cannot execute updateBatchById Method. Cause", e); } return true; } @Override public T selectById(Serializable id) { return baseMapper.selectById(id); } @Override public List<T> selectBatchIds(Collection<? extends Serializable> idList) { return baseMapper.selectBatchIds(idList); } @Override public List<T> selectByMap(Map<String, Object> columnMap) { return baseMapper.selectByMap(columnMap); } @Override public T selectOne(Wrapper<T> wrapper) { return SqlHelper.getObject(baseMapper.selectList(wrapper)); } @Override public Map<String, Object> selectMap(Wrapper<T> wrapper) { return SqlHelper.getObject(baseMapper.selectMaps(wrapper)); } @Override public Object selectObj(Wrapper<T> wrapper) { return SqlHelper.getObject(baseMapper.selectObjs(wrapper)); } @Override public int selectCount(Wrapper<T> wrapper) { return SqlHelper.retCount(baseMapper.selectCount(wrapper)); } @Override public List<T> selectList(Wrapper<T> wrapper) { return baseMapper.selectList(wrapper); } @Override public Page<T> selectPage(Page<T> page) { return selectPage(page, Condition.EMPTY); } @Override public List<Map<String, Object>> selectMaps(Wrapper<T> wrapper) { return baseMapper.selectMaps(wrapper); } @Override public List<Object> selectObjs(Wrapper<T> wrapper) { return baseMapper.selectObjs(wrapper); } @Override public Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper) { SqlHelper.fillWrapper(page, wrapper); page.setRecords(baseMapper.selectMapsPage(page, wrapper)); return page; } @Override public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper) { SqlHelper.fillWrapper(page, wrapper); page.setRecords(baseMapper.selectPage(page, wrapper)); return page; } }
能夠發現它們基本是同樣的。而在ServiceImpl中能夠發現基本方法都加上了事務。
事務又是什麼呢?
事務具備四大特性:
(1)原子性
答:原子性是指事務包含的全部操做要麼所有成功,要麼所有失敗回滾。
(2)一致性
答:一致性是指事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態,也就是說一個事務執行以前和執行以後都必須處於一致性狀態。
拿轉帳來講,假設用戶A和用戶B二者的錢加起來一共是1000,那麼無論A和B之間如何轉帳,轉幾回帳,事務結束後兩個用戶的錢相加起來應該還得是1000,這就是事務的一致性。
(3)隔離性
答:隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離。
即要達到這麼一種效果:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始以前就已經結束,要麼在T1結束以後纔開始,這樣每一個事務都感受不到有其餘事務在併發地執行
(4)持久性
答:持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即使是在數據庫系統遇到故障的狀況下也不會丟失提交事務的操做。
例如咱們在使用JDBC操做數據庫時,在提交事務方法後,提示用戶事務操做完成,當咱們程序執行完成直到看到提示後,就能夠認定事務以及正確提交,即便這時候數據庫出現了問題,也必需要將咱們的事務徹底執行完成,不然就會形成咱們看到提示事務處理完畢,可是數據庫由於故障而沒有執行事務的重大錯誤。
開發中對於對數據庫中表數據的改動是十分有必要加上事務的,不然前一個方法執行成功,後一個方法失敗,最後數據添加成功,這就尷尬了。就好比取錢,這個例子最經典,好比我有一萬存在銀行,我最後取出了二萬,對我來講發了一筆小財,對於銀行而言卻損失了一萬。對於交易相關的項目加上事務是十分必要的。
最後來一個單元測試:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring/spring.xml") public class JunitTest { @Autowired private UserDao ud; @Test public void testName() throws Exception { UserEntity userEntity = ud.selectById(1); System.out.println(userEntity.getCreateTime()); } }
從這裏看,其實與咱們原來的單元測試並沒有區別,所以對於ssm框架用熟練的人,哪怕不是很熟練也可很是容易接受的。
關於mybatis plus的註解和反射到時我會抽時間寫一個系列與你們分享