首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MyBatis-Plus 之Service CRUD 接口

MyBatis-Plus 之Service CRUD 接口

作者头像
默 语
发布于 2024-11-20 02:38:41
发布于 2024-11-20 02:38:41
25800
代码可运行
举报
文章被收录于专栏:JAVAJAVA
运行总次数:0
代码可运行
Service CRUD 接口

博主 默语带您 Go to New World.个人主页—— 默语 的博客👦🏻 《java 面试题大全》 🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭 《MYSQL从入门到精通》数据库是开发者必会基础之一~ 🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄之助。苟未尽善尽美,敬请批评指正,以资改进。!💻⌨

IService 接口: IService是MyBatis-Plus提供的通用Service接口,用于提供CRUD操作。它继承自Spring的org.springframework.data.service.CrudRepository接口,具有常见的CRUD方法。

自定义Service 接口: 除了通用的IService接口外,您还可以根据业务需求创建自定义的Service接口,继承IService,并在其中添加业务相关的方法。

BaseService 实现类: MyBatis-Plus提供了BaseService类作为IService的默认实现,它继承了Spring的org.springframework.data.service.support.CrudServiceImpl,提供了常见的CRUD实现。

业务方法扩展: 您可以在自定义Service接口中添加业务方法,这些方法可以在Service实现类中进行具体实现。这些业务方法不仅可以包含基本的CRUD操作,还可以进行复杂的业务逻辑处理。

Service 方法示例: 假设您有一个User实体类,可以通过自定义的UserService接口来执行一些特定的业务操作,例如根据用户名查询用户。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface UserService extends IService<User> {
    User findByUsername(String username);
}

使用注解: 在自定义的Service接口中,您可以使用@Service注解来标记该接口为Spring的服务组件。同时,您可以使用@Override注解来覆盖默认的Service方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public interface UserService extends IService<User> {
    @Override
    User getById(Serializable id);
    
    User findByUsername(String username);
}

通过使用MyBatis-Plus提供的通用IService接口以及自定义Service接口,您可以轻松地执行CRUD操作,同时还能够扩展业务方法来满足特定需求。这样,您可以更加专注于业务逻辑的实现,而不需要关心繁琐的数据库操作。


文章顺序及整体目录可查看(点我即可)

1.0 Service CRUD 接口

1.1 IService接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * Copyright (c) 2011-2020, baomidou (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>
 * https://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.extension.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 顶级 Service
 *
 * @author hubin
 * @since 2018-06-23
 */
public interface IService<T> {

    /**
     * 默认批次提交数量
     */
    int DEFAULT_BATCH_SIZE = 1000;

    /**
     * 插入一条记录(选择字段,策略插入)
     *
     * @param entity 实体对象
     */
    default boolean save(T entity) {
        return SqlHelper.retBool(getBaseMapper().insert(entity));
    }

    /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean saveBatch(Collection<T> entityList) {
        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     */
    boolean saveBatch(Collection<T> entityList, int batchSize);

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean saveOrUpdateBatch(Collection<T> entityList) {
        return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     * @param batchSize  每次的数量
     */
    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     */
    default boolean removeById(Serializable id) {
        return SqlHelper.retBool(getBaseMapper().deleteById(id));
    }

    /**
     * 根据 columnMap 条件,删除记录
     *
     * @param columnMap 表字段 map 对象
     */
    default boolean removeByMap(Map<String, Object> columnMap) {
        Assert.notEmpty(columnMap, "error: columnMap must not be empty");
        return SqlHelper.retBool(getBaseMapper().deleteByMap(columnMap));
    }

    /**
     * 根据 entity 条件,删除记录
     *
     * @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default boolean remove(Wrapper<T> queryWrapper) {
        return SqlHelper.retBool(getBaseMapper().delete(queryWrapper));
    }

    /**
     * 删除(根据ID 批量删除)
     *
     * @param idList 主键ID列表
     */
    default boolean removeByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        return SqlHelper.retBool(getBaseMapper().deleteBatchIds(idList));
    }

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     */
    default boolean updateById(T entity) {
        return SqlHelper.retBool(getBaseMapper().updateById(entity));
    }

    /**
     * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    default boolean update(Wrapper<T> updateWrapper) {
        return update(null, updateWrapper);
    }

    /**
     * 根据 whereEntity 条件,更新记录
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    default boolean update(T entity, Wrapper<T> updateWrapper) {
        return SqlHelper.retBool(getBaseMapper().update(entity, updateWrapper));
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatchById(Collection<T> entityList) {
        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     */
    boolean updateBatchById(Collection<T> entityList, int batchSize);

    /**
     * TableId 注解存在更新记录,否插入一条记录
     *
     * @param entity 实体对象
     */
    boolean saveOrUpdate(T entity);

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    default T getById(Serializable id) {
        return getBaseMapper().selectById(id);
    }

    /**
     * 查询(根据ID 批量查询)
     *
     * @param idList 主键ID列表
     */
    default List<T> listByIds(Collection<? extends Serializable> idList) {
        return getBaseMapper().selectBatchIds(idList);
    }

    /**
     * 查询(根据 columnMap 条件)
     *
     * @param columnMap 表字段 map 对象
     */
    default List<T> listByMap(Map<String, Object> columnMap) {
        return getBaseMapper().selectByMap(columnMap);
    }

    /**
     * 根据 Wrapper,查询一条记录 <br/>
     * <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default T getOne(Wrapper<T> queryWrapper) {
        return getOne(queryWrapper, true);
    }

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     */
    T getOne(Wrapper<T> queryWrapper, boolean throwEx);

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    Map<String, Object> getMap(Wrapper<T> queryWrapper);

    /**
     * 根据 Wrapper,查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param mapper       转换函数
     */
    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

    /**
     * 查询总记录数
     *
     * @see Wrappers#emptyWrapper()
     */
    default int count() {
        return count(Wrappers.emptyWrapper());
    }

    /**
     * 根据 Wrapper 条件,查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default int count(Wrapper<T> queryWrapper) {
        return SqlHelper.retCount(getBaseMapper().selectCount(queryWrapper));
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default List<T> list(Wrapper<T> queryWrapper) {
        return getBaseMapper().selectList(queryWrapper);
    }

    /**
     * 查询所有
     *
     * @see Wrappers#emptyWrapper()
     */
    default List<T> list() {
        return list(Wrappers.emptyWrapper());
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
        return getBaseMapper().selectPage(page, queryWrapper);
    }

    /**
     * 无条件翻页查询
     *
     * @param page 翻页对象
     * @see Wrappers#emptyWrapper()
     */
    default <E extends IPage<T>> E page(E page) {
        return page(page, Wrappers.emptyWrapper());
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
        return getBaseMapper().selectMaps(queryWrapper);
    }

    /**
     * 查询所有列表
     *
     * @see Wrappers#emptyWrapper()
     */
    default List<Map<String, Object>> listMaps() {
        return listMaps(Wrappers.emptyWrapper());
    }

    /**
     * 查询全部记录
     */
    default List<Object> listObjs() {
        return listObjs(Function.identity());
    }

    /**
     * 查询全部记录
     *
     * @param mapper 转换函数
     */
    default <V> List<V> listObjs(Function<? super Object, V> mapper) {
        return listObjs(Wrappers.emptyWrapper(), mapper);
    }

    /**
     * 根据 Wrapper 条件,查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default List<Object> listObjs(Wrapper<T> queryWrapper) {
        return listObjs(queryWrapper, Function.identity());
    }

    /**
     * 根据 Wrapper 条件,查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param mapper       转换函数
     */
    default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
        return getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
        return getBaseMapper().selectMapsPage(page, queryWrapper);
    }

    /**
     * 无条件翻页查询
     *
     * @param page 翻页对象
     * @see Wrappers#emptyWrapper()
     */
    default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
        return pageMaps(page, Wrappers.emptyWrapper());
    }

    /**
     * 获取对应 entity 的 BaseMapper
     *
     * @return BaseMapper
     */
    BaseMapper<T> getBaseMapper();

    /**
     * 以下的方法使用介绍:
     *
     * 一. 名称介绍
     * 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作
     * 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的
     *
     * 二. 支持介绍
     * 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作
     * 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作
     *
     * 三. 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推
     * 1. 根据条件获取一条数据: `query().eq("column", value).one()`
     * 2. 根据条件删除一条数据: `update().eq("column", value).remove()`
     *
     */

    /**
     * 链式查询 普通
     *
     * @return QueryWrapper 的包装类
     */
    default QueryChainWrapper<T> query() {
        return ChainWrappers.queryChain(getBaseMapper());
    }

    /**
     * 链式查询 lambda 式
     * <p>注意:不支持 Kotlin </p>
     *
     * @return LambdaQueryWrapper 的包装类
     */
    default LambdaQueryChainWrapper<T> lambdaQuery() {
        return ChainWrappers.lambdaQueryChain(getBaseMapper());
    }

    /**
     * 链式更改 普通
     *
     * @return UpdateWrapper 的包装类
     */
    default UpdateChainWrapper<T> update() {
        return ChainWrappers.updateChain(getBaseMapper());
    }

    /**
     * 链式更改 lambda 式
     * <p>注意:不支持 Kotlin </p>
     *
     * @return LambdaUpdateWrapper 的包装类
     */
    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
        return ChainWrappers.lambdaUpdateChain(getBaseMapper());
    }

    /**
     * <p>
     * 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
     * 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)
     * </p>
     *
     * @param entity 实体对象
     */
    default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
        return update(entity, updateWrapper) || saveOrUpdate(entity);
    }
}

1.1 ServiceImpl实现类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * Copyright (c) 2011-2020, baomidou (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>
 * https://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.extension.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionHolder;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
 *
 * @author hubin
 * @since 2018-06-23
 */
@SuppressWarnings("unchecked")
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

    protected Log log = LogFactory.getLog(getClass());

    @Autowired
    protected M baseMapper;

    @Override
    public M getBaseMapper() {
        return baseMapper;
    }

    protected Class<?> entityClass = currentModelClass();

    /**
     * 判断数据库操作是否成功
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     * @deprecated 3.3.1
     */
    @Deprecated
    protected boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    protected Class<T> currentModelClass() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(getClass(), 1);
    }

    /**
     * 批量操作 SqlSession
     *
     * @deprecated 3.3.0
     */
    @Deprecated
    protected SqlSession sqlSessionBatch() {
        return SqlHelper.sqlSessionBatch(entityClass);
    }

    /**
     * 释放sqlSession
     *
     * @param sqlSession session
     * @deprecated 3.3.0
     */
    @Deprecated
    protected void closeSqlSession(SqlSession sqlSession) {
        SqlSessionUtils.closeSqlSession(sqlSession, GlobalConfigUtils.currentSessionFactory(entityClass));
    }

    /**
     * 获取 SqlStatement
     *
     * @param sqlMethod ignore
     * @return ignore
     */
    protected String sqlStatement(SqlMethod sqlMethod) {
        return SqlHelper.table(entityClass).getSqlStatement(sqlMethod.getMethod());
    }

    /**
     * 批量插入
     *
     * @param entityList ignore
     * @param batchSize  ignore
     * @return ignore
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveBatch(Collection<T> entityList, int batchSize) {
        String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
        return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
    }

    /**
     * TableId 注解存在更新记录,否插入一条记录
     *
     * @param entity 实体对象
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveOrUpdate(T entity) {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
            String keyProperty = tableInfo.getKeyProperty();
            Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
            Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
            return StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal)) ? save(entity) : updateById(entity);
        }
        return false;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
            Object idVal = ReflectionKit.getMethodValue(entityClass, entity, keyProperty);
            if (StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal))) {
                sqlSession.insert(tableInfo.getSqlStatement(SqlMethod.INSERT_ONE.getMethod()), entity);
            } else {
                MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                param.put(Constants.ENTITY, entity);
                sqlSession.update(tableInfo.getSqlStatement(SqlMethod.UPDATE_BY_ID.getMethod()), param);
            }
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
        String sqlStatement = sqlStatement(SqlMethod.UPDATE_BY_ID);
        return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
            param.put(Constants.ENTITY, entity);
            sqlSession.update(sqlStatement, param);
        });
    }

    @Override
    public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
        if (throwEx) {
            return baseMapper.selectOne(queryWrapper);
        }
        return SqlHelper.getObject(log, baseMapper.selectList(queryWrapper));
    }

    @Override
    public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
        return SqlHelper.getObject(log, baseMapper.selectMaps(queryWrapper));
    }

    @Override
    public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
        return SqlHelper.getObject(log, listObjs(queryWrapper, mapper));
    }

    /**
     * 执行批量操作
     *
     * @param consumer consumer
     * @since 3.3.0
     * @deprecated 3.3.1 后面我打算移除掉 {@link #executeBatch(Collection, int, BiConsumer)} }.
     */
    @Deprecated
    protected boolean executeBatch(Consumer<SqlSession> consumer) {
        SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(entityClass);
        SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
        boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
        if (sqlSessionHolder != null) {
            SqlSession sqlSession = sqlSessionHolder.getSqlSession();
            //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
            //按道理来说,这里的值应该一直为false。
            sqlSession.commit(!transaction);
        }
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        if (!transaction) {
            log.warn("SqlSession [" + sqlSession + "] was not registered for synchronization because DataSource is not transactional");
        }
        try {
            consumer.accept(sqlSession);
            //非事物情况下,强制commit。
            sqlSession.commit(!transaction);
            return true;
        } catch (Throwable t) {
            sqlSession.rollback();
            Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
            if (unwrapped instanceof RuntimeException) {
                MyBatisExceptionTranslator myBatisExceptionTranslator
                    = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
                throw Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));
            }
            throw ExceptionUtils.mpe(unwrapped);
        } finally {
            sqlSession.close();
        }
    }

    /**
     * 执行批量操作
     *
     * @param list      数据集合
     * @param batchSize 批量大小
     * @param consumer  执行方法
     * @param <E>       泛型
     * @return 操作结果
     * @since 3.3.1
     */
    protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
        Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
        return !CollectionUtils.isEmpty(list) && executeBatch(sqlSession -> {
            int size = list.size();
            int i = 1;
            for (E element : list) {
                consumer.accept(sqlSession, element);
                if ((i % batchSize == 0) || i == size) {
                    sqlSession.flushStatements();
                }
                i++;
            }
        });
    }

    /**
     * 执行批量操作(默认批次提交数量{@link IService#DEFAULT_BATCH_SIZE})
     *
     * @param list     数据集合
     * @param consumer 执行方法
     * @param <E>      泛型
     * @return 操作结果
     * @since 3.3.1
     */
    protected <E> boolean executeBatch(Collection<E> list, BiConsumer<SqlSession, E> consumer) {
        return executeBatch(list, DEFAULT_BATCH_SIZE, consumer);
    }
}

2.0 实现IService接口

我们有了之前学习BaseMapd的经验之后我们来看些mapper的自带的service的方法有哪些妙用;

2.1 创建Service 层Impl 层

**UserService:**继承了mapper-plus的IService

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.pojo.User;

public interface UserService extends IService<User> {

}

**UserServiceImpl:**继承了mapper-plus的ServiceImpl;我们传入的2个值一个是mapper(mapper接口)一个是user(实体类)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.service.Impl;

import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import com.example.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserSercieImpl extends ServiceImpl<UserMapper,User> implements UserService {
}

2.2 写测试类

新建 MyBatisPlusService 测试类;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example;

import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MYBatisPlusService {

     //引用servies的方法
    @Autowired
    private UserService userService;

    
}

2.3 查询全部条数;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
     * 查询总条数
     */
    @Test
    public void SelectCount(){
         int count = userService.count();
        System.out.println("count"+count);

    }

执行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==>  Preparing: SELECT COUNT( 1 ) FROM user 
==> Parameters: 
<==    Columns: COUNT( 1 )
<==        Row: 5
<==      Total: 1

2.4 根据id删除;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 根据id删除
     */
    @Test
    public void removeById(){
        boolean count = userService.removeById(3L);
        System.out.println("count"+count);
        if (count){
            System.out.println("删除成功");
        }else {
            System.out.println("删除失败");
        }

运行结果是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==>  Preparing: DELETE FROM user WHERE id=? 
==> Parameters: 3(Long)
<==    Updates: 1

2.5 批量添加;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 批量添加
     */
    @Test
    public void removeById1(){
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("闫文超"+i);
            user.setAge(10+i);
            user.setEmail("757631644"+i+i+1);
        list.add(user);
        }

        boolean count = userService.saveBatch(list);
        System.out.println("count"+count);
        if (count){
            System.out.println("批量添加成功");
        }else {
            System.out.println("批量添加失败");
        }

    }

运行结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
==>  Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) 
==> Parameters: 1577321026130407426(Long), 闫文超0(String), 10(Integer), 757631644001(String)
==> Parameters: 1577321026298179585(Long), 闫文超1(String), 11(Integer), 757631644111(String)
==> Parameters: 1577321026298179586(Long), 闫文超2(String), 12(Integer), 757631644221(String)
==> Parameters: 1577321026298179587(Long), 闫文超3(String), 13(Integer), 757631644331(String)
==> Parameters: 1577321026298179588(Long), 闫文超4(String), 14(Integer), 757631644441(String)
==> Parameters: 1577321026298179589(Long), 闫文超5(String), 15(Integer), 757631644551(String)
==> Parameters: 1577321026298179590(Long), 闫文超6(String), 16(Integer), 757631644661(String)
==> Parameters: 1577321026298179591(Long), 闫文超7(String), 17(Integer), 757631644771(String)
==> Parameters: 1577321026298179592(Long), 闫文超8(String), 18(Integer), 757631644881(String)
==> Parameters: 1577321026298179593(Long), 闫文超9(String), 19(Integer), 757631644991(String)
counttrue
批量添加成功

此次service的演示到此为止;大家也可以根据接口实现去看看都有哪些实现;大家也可以去尝试下其他的玩法;由于内容太过简单;我这边就不多做介绍了;

大家有任何问题都可以留言;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux笔记(18)| 线程基础(二)
上一节里讲了线程的基本概念,和进程的关系等等。这一节来深入一些,讲一讲具体的一些知识。
飞哥
2020/11/25
6410
Linux笔记(18)| 线程基础(二)
linux网络编程之posix 线程(二):线程的属性和 线程特定数据 Thread-specific Data
本文介绍了多线程和多进程的区别,从多个方面进行对比,包括资源占用、调度开销、并发度、线程局部存储、线程间通信、资源竞争、性能评估等方面。同时,还介绍了多线程在操作系统、数据库、网络编程、高性能计算等领域的应用,以及多线程技术的未来展望。
s1mba
2017/12/28
1.1K0
linux网络编程之posix 线程(二):线程的属性和 线程特定数据 Thread-specific Data
12(线程控制)
线程属性主要有: (1)线程的分离状态属性detachstate, (2)线程栈末尾的警戒缓冲区大小guardsize, (3)线程栈的最低地址statckaddr, (4)线程栈的大小stacksize。 如果对现有某个线程的终止状态不感兴趣的话,可以使用pthread_detach函数让操作系统在线程退出时候收回它所占用的资源。
提莫队长
2019/02/21
5800
多线程编程C语言版
什么是多线程,提出这个问题的时候,我还是很老实的拿出操作系统的书,按着上面的话敲下“为了减少进程切换和创建开销,提高执行效率和节省资源,我们引入了线程的概念,与进程相比较,线程是CPU调度的一个基本单位。”
DeROy
2021/11/16
3.8K0
多线程编程C语言版
线程源码分析之specific.c(基于linuxthreads2.0.1)
该文件是线程私有数据的实现。在线程tcb里有一个数组,保存了一系列的键对值。从而实现了线程的私有数据存储。线程想拥有自己的数据时,首先获取一个键,然后在tcb中保存一个键对值即可。
theanarkh
2019/10/08
1.1K0
Linux下多线程编程详解简介
上面的代码很简单,就是启动一个线程,然后先线程里循环打印字段字符串。我们就以这个最简单的例子来开口。
用户2929716
2018/08/23
4.4K0
Linux多线程Pthread学习小结
POSIX thread 简称为pthread,Posix线程是一个POSIX标准线程.该标准定义内部API创建和操纵线程.
阳光岛主
2019/02/20
2.2K0
POSIX之Thread-Specific Data
进程里的多个线程,共享该进程的全局变量。Posix定义了一种Thread-Specific Data,它看起来是个全局变量,所有线程都可以使用它,而它的值在每一个线程中又是单独存储的。
Taishan3721
2022/12/05
2770
try-catch 的实现
基本所有的编程语言都会有异常捕捉的语法,try-catch 基本是所有编程语言都会有的信息,他会捕捉 try 中语法错误,如果存在语法错误就会执行 catch 的内容。
ge3m0r
2024/06/01
2920
【线程同步】条件变量
条件变量不是锁,它经常和互斥量组合使用。以生产者消费者模型为例,当前有多个消费者线程竞争一个资源,当资源为空时,消费者线程会阻塞在一个条件上,等待生产者通知,生产者写数据到临界区并通知消费者,此时消费者去竞争这个资源并读取数据。它是这样实现的,第一个线程访问资源的时候,获得互斥锁,调用pthread_cond_wait将会释放锁,并阻塞在条件cond上面,这是第二个线程到来,依然可以获得互斥锁,然后这个线程如果调用pthread_cond_wait也会会释放锁,并阻塞在条件cond上面,这样,所有线程就都阻塞在cond上面。
mindtechnist
2024/08/08
2400
【线程同步】条件变量
Linux同步机制(二) - 条件变量,信号量,文件锁,栅栏
1 条件变量 条件变量是一种同步机制,允许线程挂起,直到共享数据上的某些条件得到满足。 1.1 相关函数  #include <pthread.h>  pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t*cond_attr);  int pthread_cond_signal(pthread_cond_t *cond);  int
三丰SanFeng
2018/01/16
3.1K0
『腾讯后台开发』实习生技能要求
如题,应届生除了要良好地掌握算法和数据结构以外,以下一些技能点列表希望对大家有帮助,有兴趣的朋友可以参考这个针对性地补缺补差。文章列出的技能点有的要求熟悉,有的了解即可,注意技能点前面的修饰词。如果没有明确给出“熟悉”“了解”等字眼,要求均为熟悉。 一、操作系统方面 多线程相关与线程之间同步技术 熟练使用(但不局限于)以下linux API linux下的线程创建、等待、获取线程id 1int pthread_create(pthread_t *thread, const pthread_attr_t *
范蠡
2018/07/25
9400
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝慢慢看(2)
什么叫互斥量,顾名思义就是咱这么多人,只能有一个使用这个资源,就像共享小单车,一次只能给一个人用,一个人下车锁车了,另一个人才能去扫码开锁。
看、未来
2020/08/25
4890
Posix线程 它们那一大家子事儿,要觉得好你就收藏进被窝慢慢看(2)
linux中实现线程同步的6种方法
最后运行的结果不是固定的,有可能是0、-1,如果有这个ticket_num变量代表是库存的话,那么就会出现库存为负数的情况,所以需要引入线程同步来保证线程安全。
全栈程序员站长
2022/09/14
9890
UNPv1第二十三章:线程
在传统的UNIX模型中,当一个进程需要由另一个实体执行某件事时,该进程派生(fork)一个子进程,让子进程去进行处理。UNIX下的大多数网络服务器程序都是这么编写的,这在我们的并发服务程序例子中可以看出:父进程接收连接,派生子进程,子进程处理与客户的交互。
提莫队长
2019/02/21
5240
Linux多线程编程(二)
在单线程的程序里,有两种基本的数据:全局变量和局部变量。但在多线程程序里,还有第三种数据类型:线程数据(TSD: Thread-Specific Data)。
efonfighting
2019/09/24
1.8K0
多线程的同步与互斥
等到线程1再度被唤醒时,它需要完成之前未完成的动作,它会将未来的及写回的数据再次写回,此时内存中的票数又变成了999
始终学不会
2023/10/17
3100
多线程的同步与互斥
Linux多线程编程(不限Linux)
 线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步、互斥,这些东西将在本文中介绍。我见到这样一道面试题:   是否熟悉POSIX
用户6754675
2020/03/03
4.9K0
Linux内核编程--进程控制,线程控制,锁机制
每个进程都有一个非负整型表示的唯一进程ID。进程ID是可复用的,当一个进程终止后,其进程ID也会被其他进程使用。
Coder-ZZ
2022/05/09
1.3K0
Linux内核编程--进程控制,线程控制,锁机制
POSIX之Condition Variable
Condition Variable(简称Condition)是Posix定义的一种同步机制 - Thread为了某些数据的特定状态,而阻塞执行,等待其它Thread的通知。使用时有个限制 - Condition Variable必须与Mutex关联使用。怎么感觉有点像关联到信号量的Event?
Taishan3721
2022/12/05
5970
POSIX之Condition Variable
推荐阅读
相关推荐
Linux笔记(18)| 线程基础(二)
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档