MP实战系列(四)之DAO讲解
说到DAO不得不提一个开发名词"三层架构",所谓的三层架构是什么呢?简单的可以概括为数据访问层,业务逻辑层,界面层(又称表现层).
这也是我们Java开发常用的手段,经常有人将三层架构和mvc模式混淆,在我看来,三层架构就是三层架构,mvc只是三层架构中的表现层中的架构,相当于在一个比较大的层面,往里面在细分,mvc细分,可分为模型,视图,控制器,在这里模型通常指数据,也可以叫JavaBean,而视图的话,这个视图就是展示给用户看的,通常用于视图的模板可以为jsp,freemarker,beetl,velocity或者是springboot推荐使用的thymeleaf等,当然也可以是纯html,不过需要ajax交互获取后台的数据。控制器的话,让人不禁想起了servlet,控制器的作用就相当于servlet的作用,就是对http请求进行处理。
mvc模式也是现在流行的一种软件设计模式。
三层架构可以用来做什么呢?答可以做很多,最大的作用,用一句官方的话,"高内聚,低耦合",软件开发中的大忌就是高耦合,内聚的意思我不是十分明白,不过耦合还是很让人理解的,耦合度高就是你改完这个代码,另外的也要改,再另外的又要改,对于互联网项目,需求变更是经常的,耦合度高的话,开发项目的效率将会非常低下。
我这个人比较喜欢开场博文说说行内话,现在开始讲讲我们的mybatis plus的dao吧!
首先还是那句话,贴源码分析讲解
/**
* 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中有一句经典的话,一个类只能继承一个类,但可以实现多个接口,同样一个接口可以继承多个接口
在此不得不提到一个常见的面试考题:
接口和抽象类的区别:
相同点:
(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的注解和反射到时我会抽时间写一个系列与大家分享
MP实战系列(四)之DAO讲解的更多相关文章
- MP实战系列(六)之代码生成器讲解
MP的代码生成器可谓用"简洁"二字,来形容. 我个人觉得jeesite的代码生成器都不一定比它好用.当然也是由于我个人的习惯. 只需一键执行main方法,就可以生成对应的项目文件, ...
- MP实战系列(七)之集成springboot
springboot是现在比较流行的微服使用的框架,springboot本质上就是将spring+springmvc+mybatis零配置化,基本上springboot的默认配置符合我们的开发.当然有 ...
- MP实战系列(十二)之封装方法详解(续二)
继续MP实战系列(十一)之封装方法详解(续一)这篇文章之后. 此次要讲的是关于查询. 查询是用的比较多的,查询很重要,好的查询,加上索引如鱼得水,不好的查询加再多索引也是无济于事. 1.selectB ...
- MP实战系列(十四)之分页使用
MyBatis Plus的分页,有插件式的,也有其自带了,插件需要配置,说麻烦也不是特别麻烦,不过觉得现有的MyBatis Plus足以解决,就懒得配置插件了. MyBatis Plus的资料不算是太 ...
- MP实战系列(九)之集成Shiro
下面示例是在之前的基础上进行的,大家如果有什么不明白的可以参考MP实战系列的前八章 当然,同时也可以参考MyBatis Plus官方教程 建议如果参考如下教程,使用的技术为spring+mybatis ...
- MP实战系列(二)之集成swagger
其实与spring+springmvc+mybatis集成swagger没什么区别,只是之前写的太不好了,所以这次决定详细写. 提到swagger不得不提rest,rest是一种架构风格,里面有对不同 ...
- WCF开发实战系列四:使用Windows服务发布WCF服务
WCF开发实战系列四:使用Windows服务发布WCF服务 (原创:灰灰虫的家http://hi.baidu.com/grayworm) 上一篇文章中我们通过编写的控制台程序或WinForm程序来为本 ...
- MP实战系列(三)之实体类讲解
首先说一句,mybatis plus实在太好用了! mybaits plus的实体类: 以我博客的用户类作为讲解 package com.blog.entity; import com.baomido ...
- MP实战系列(八)之SpringBoot+Swagger2
SpringBoot一个原则,爱好编程的朋友们都知道,那就是"习惯优于配置". 今天一上来主要说的还是代码,个人比较喜欢来的实战系列的,不过有的时候还是比较偏重于理论,理论是造轮子 ...
随机推荐
- mongodb 权限设置--用户名、密码、端口
转自:http://www.cnblogs.com/valor-xh/p/6369432.html 一.关于权限的默认配置 在默认情况下,mongod是监听在0.0.0.0之上的,任何客户端都可以直接 ...
- CentOS6.5安装mysql以及常见问题的解决
前言 最近在学习Linux系统,今天在安装MySQL数据库时出现很多问题,花费了两个小时终于解决,故记录下来以供大家参考.(本人目前还在学习阶段,下面写到的是自己结合网上查到的资料以及各位前辈给出的解 ...
- 解决Linux服务器tomact-8.0启动慢的问题
环境信息: CentOS release 6.8 tomcat-8.0 JDK1.8 一.启动tomcat #sh /root/tomcat-8.0/bin/startup.sh #tailf /ro ...
- 禁用 Gnome Shell 默认的 Ubuntu Dock 和 Ubuntu AppIndicators 扩展
以前折腾的时候禁用过,现在已经忘记目录了,结果今天手贱把系统从 18.04 升级到了 18.10 ,很多东西都要重新搞过,而且用惯了 mac 已经不熟悉 linux 上瞎折腾的那一套了,简直坑爹.. ...
- npm 走 privoxy 代理经常出现 shasum check failed 的解决办法
今天在下载一个比较大的项目,经常 shasum check failed ,太烦了,于是想切淘宝源,分别尝试 nrm 切换和传递 --registry ,结果都出现 Unexpected end of ...
- 微信小程序踩过的一些坑
前言 迄今为止,正儿八经的上线了真正意义上的程序,但是这个小程序却着实不小. 之所以不小,是因为这个类似于社区的小程序,已经做了大部分都有的功能了 举例说明,具体的一些功能点: 1.帖子列表页面:会有 ...
- js 中判断变量是数组还是对象,和判断对象是否为空
判断是对象还是数组 var ids={ id:'1',num:'2' } if(Array.isArray(ids) == false) {console.log('不是数组,对象') } else ...
- iOS动画-从UIView到Core Animation
首先,介绍一下UIView相关的动画. UIView普通动画: [UIView beginAnimations: context:]; [UIView commitAnimations]; 动画属性设 ...
- (后端)Java新人入职——配置环境及安装开发工具(完全)
转自csdn:执笔记忆的空白 很多新人对于进入新公司,相关工具的安装和环境变量的设定很苦恼.又苦于没有完整的配置开发环境的资料,我这里写一篇操作步骤的案例, 至少让你能把开发工具安装起来,并实用起来, ...
- csdn中使用git的一些注意事项---免得走弯路
csdn中使用git必须的条件(windows系统下): 1.本机当前登录用户文件夹下必须有.ssh隐藏文件,并且这个文件中必须有用git bash中用命令生成的密钥文件:id_rsa id_rsa ...