SpringBoot与MyBatis零XML配置集成和集成测试
1.SpringBoot与MyBatis零XML配置集成和集成测试
2.Maven多模块项目架构配置介绍和实战3.SpringBoot如何让业务Bean优先于其他Bean加载4.Flutter/Dart第01天:Dart安装和初体验5.Flutter/Dart第02天:Dart基础语法(建议收藏)6.Flutter/Dart第03天:Dart可迭代集合7.Flutter/Dart第04天:Dart异步编程(Future和async/await)8.Flutter/Dart第05天:Dart特殊特性Mixin详解9.Flutter/Dart第06天:Dart基础语法详解(变量)10.Flutter/Dart第07天:Dart基础语法详解(库、导入和关键字)11.Flutter/Dart第08天:Dart类型(内置类型、记录、集合、泛型和类型别名)12.Flutter/Dart第09天:Dart高级特性Pattern模式的概览和用法13.Flutter/Dart第10天:Dart高级特性Pattern模式的全部类型(共15种)14.Flutter/Dart第11天:Dart函数方法详解15.Flutter/Dart第12天:Dart控制流详解16.Flutter/Dart第13天:Dart错误处理17.Mac电脑80端口被占用的2种解决办法18.Flutter/Dart第14天:Dart类详解19.Flutter/Dart第15天:Dart类构造函数20.Flutter/Dart第16天:Dart类方法21.Flutter/Dart第17天:Dart类继承22.Flutter/Dart第18天:Dart特性之可调用对象23.Flutter/Dart第19天:Dart高级特性之扩展方法(Extension methods)24.Flutter/Dart第20天:Dart 3.0新特性之类型修饰符25.Flutter/Dart第21天:Dart异步编程(Future/Stream)26.FlutterApp实战·第01天:Flutter安装和配置27.Python深入理解*和**含义和应用28.[每日AI·0430]首个自主更新的多模态大模型,马斯克访华,文本一键转3D数字人骨骼动画,创新的虚拟试衣模型29.国内免费的AI工具出色地帮我辅导女儿的小学英语作业30.[每日AI·0506]巴菲特谈 AI,李飞飞创业,苹果或将推出 AI 功能,ChatGPT 版搜索引擎31.玩转AI,笔记本电脑安装属于自己的Llama 3 8B大模型和对话客户端32.一文彻底整明白,基于Ollama工具的LLM大语言模型Web可视化对话机器人部署指南33.基于Llama 3搭建中文版(Llama3-Chinese-Chat)大模型对话聊天机器人34.Python游戏编程:一步步用Python打造经典贪吃蛇小游戏35.借助AI大模型,三分钟原创一部儿童故事短视频(附完整操作步骤)36.[AI资讯·0531] 达摩院医疗AI新里程碑,OpenAI价值数十亿美元,微软投资130亿美元,百度文库成为一站式AI内容获取与创作平台,三大运营商完成AI产品市场,AI获得成功PMF需多次尝试……37.ngrok内网穿透,实现外网访问ChatTTS/Qwen2等大模型应用原文地址:https://ntopic.cn/p/2023070801/
源代码先行:
- Gitee本文介绍的完整仓库:https://gitee.com/obullxl/ntopic-boot
- GitHub本文介绍的完整仓库:https://github.com/obullxl/ntopic-boot
背景介绍
在Java众多的ORM框架里面,MyBatis是比较轻量级框架之一,既有数据表和Java对象映射功能,在SQL编写方面又不失原生SQL的特性。SpringBoot提倡使用注解代替XML配置,同样的,在集成MyBatis时也可以做到全注解化,无XML配置。相关的集成方法网上存在大量的教程,本文是个人在实际项目过程的一个备忘,并不是复制和粘贴,同时在本文后面提供了完整的集成测试用例。
MyBatis集成
涉及到以下4个方面:
- 我们Maven工程是一个SpringBoot工程
- 引入MyBatis的Starter依赖
- SpringBoot工程配置中增加MyBatis的配置
- Mapper/DAO通过注解实现
SpringBoot工程依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.3</version> <relativePath/> </parent> <!-- 其他部分省略 --> </project>
MyBatis Starter依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 其他省略 --> <dependencyManagement> <dependencies> <!-- MyBatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <!-- SQLite --> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.39.2.0</version> <scope>provided</scope> </dependency> <!-- Druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.2</version> </dependency> <!-- 其他省略 --> </dependencies> </dependencyManagement> <!-- 其他省略 --> </project>
SpringBoot Main配置
- application.properties配置,增加DB数据源:
# # 数据库:url值设置成自己的文件路径 # ntopic.datasource.driver-class-name=org.sqlite.JDBC ntopic.datasource.url=jdbc:sqlite:./../NTopicBoot.sqlite ntopic.datasource.userName= ntopic.datasource.password=
MapperScan
注解:指明MyBatis的Mapper在哪写包中,cn.ntopic.das..**.dao
指明,我们的Mapper类所在的包
/** * Author: obullxl@163.com * Copyright (c) 2020-2021 All Rights Reserved. */ package cn.ntopic; import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.Configuration; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.support.TransactionTemplate; import javax.sql.DataSource; /** * NTopic启动器 * * @author obullxl 2021年06月05日: 新增 */ @SpringBootApplication @MapperScan(basePackages = "cn.ntopic.das..**.dao", sqlSessionFactoryRef = "ntSqlSessionFactory") public class NTBootApplication { /** * SpringBoot启动 */ public static void main(String[] args) { SpringApplication.run(NTBootApplication.class, args); } /** * DataSource配置 */ @Bean(name = "ntDataSource", initMethod = "init", destroyMethod = "close") public DruidDataSource ntDataSource(@Value("${ntopic.datasource.url}") String url , @Value("${ntopic.datasource.userName}") String userName , @Value("${ntopic.datasource.password}") String password) { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(url); dataSource.setUsername(userName); dataSource.setPassword(password); dataSource.setInitialSize(0); dataSource.setMinIdle(1); dataSource.setMaxActive(5); dataSource.setMaxWait(3000L); return dataSource; } /** * MyBatis事务配置 */ @Bean("ntSqlSessionFactory") public SqlSessionFactoryBean ntSqlSessionFactory(@Qualifier("ntDataSource") DataSource dataSource) { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); Configuration configuration = new Configuration(); configuration.setMapUnderscoreToCamelCase(true); sqlSessionFactoryBean.setConfiguration(configuration); return sqlSessionFactoryBean; } /** 其他代码省略 */ }
MyBatis Mapper类/DAO类
几个核心的注解:
- Insert插入
- Select查询
- Update更新
- Delete删除
/** * Author: obullxl@163.com * Copyright (c) 2020-2021 All Rights Reserved. */ package cn.ntopic.das.dao; import cn.ntopic.das.model.UserBaseDO; import org.apache.ibatis.annotations.*; import org.springframework.stereotype.Repository; import java.util.Date; import java.util.List; /** * @author obullxl 2021年10月17日: 新增 */ @Repository("userBaseDAO") public interface UserBaseDAO { /** * 新增用户记录 */ @Insert("INSERT INTO nt_user_base (id, name, password, role_list, ext_map, create_time, modify_time)" + " VALUES (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{roleList,jdbcType=VARCHAR}, #{extMap,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyTime,jdbcType=TIMESTAMP})") void insert(UserBaseDO userBaseDO); /** * 根据ID查询记录 */ @Select("SELECT * FROM nt_user_base WHERE id = #{id,jdbcType=VARCHAR}") UserBaseDO selectById(@Param("id") String id); /** * 根据名称查询记录 */ @Select("SELECT * FROM nt_user_base WHERE name = #{name,jdbcType=VARCHAR}") UserBaseDO selectByName(@Param("name") String name); /** * 查询所有用户 */ @Select("SELECT * FROM nt_user_base LIMIT 30") List<UserBaseDO> select(); /** * 更新角色列表 * FIXME: SQLite/MySQL 当前时间函数不一致,本次通过入参传入! */ @Update("UPDATE nt_user_base SET modify_time=#{modifyTime,jdbcType=TIMESTAMP}, role_list=#{roleList,jdbcType=VARCHAR} WHERE id=#{id,jdbcType=VARCHAR}") int updateRoleList(@Param("id") String id, @Param("modifyTime") Date modifyTime, @Param("roleList") String roleList); /** * 删除用户记录 */ @Delete("DELETE FROM nt_user_base WHERE id = #{id,jdbcType=VARCHAR}") int deleteById(@Param("id") String id); /** * 删除用户记录 */ @Delete("DELETE FROM nt_user_base WHERE name = #{name,jdbcType=VARCHAR}") int deleteByName(@Param("name") String name); }
集成测试(包括CRUD操作)
/** * Author: obullxl@163.com * Copyright (c) 2020-2021 All Rights Reserved. */ package cn.ntopic.das.dao; import cn.ntopic.das.model.UserBaseDO; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringRunner; import java.util.Date; /** * @author obullxl 2021年10月17日: 新增 */ @SpringBootTest @RunWith(SpringRunner.class) public class UserBaseDAOTest extends AbstractJUnit4SpringContextTests { @Autowired @Qualifier("userBaseDAO") private UserBaseDAO userBaseDAO; /** * CRUD简单测试 */ @Test public void test_insert_select_update_delete() { final String id = "ID-" + RandomUtils.nextLong(); final String name = "NAME-" + RandomUtils.nextLong(); // 1. 清理数据 this.userBaseDAO.deleteById(id); this.userBaseDAO.deleteByName(name); // 请求数据 - 验证 UserBaseDO userBaseDO = this.userBaseDAO.selectById(id); Assert.assertNull(userBaseDO); userBaseDO = this.userBaseDAO.selectByName(name); Assert.assertNull(userBaseDO); try { // 2. 新增数据 UserBaseDO newUserDO = new UserBaseDO(); newUserDO.setId(id); newUserDO.setName(name); newUserDO.setCreateTime(new Date()); newUserDO.setModifyTime(new Date()); this.userBaseDAO.insert(newUserDO); // 3. 数据查询 - 新增验证 UserBaseDO checkUserDO = this.userBaseDAO.selectById(id); Assert.assertNotNull(checkUserDO); Assert.assertEquals(name, checkUserDO.getName()); Assert.assertNotNull(checkUserDO.getCreateTime()); Assert.assertNotNull(checkUserDO.getModifyTime()); Assert.assertTrue(StringUtils.isBlank(checkUserDO.getRoleList())); // 4. 更新数据 int update = this.userBaseDAO.updateRoleList(id, new Date(), "ADMIN,DATA"); Assert.assertEquals(1, update); // 更新数据 - 验证 checkUserDO = this.userBaseDAO.selectById(id); Assert.assertNotNull(checkUserDO); Assert.assertEquals("ADMIN,DATA", checkUserDO.getRoleList()); // 5. 数据删除 int delete = this.userBaseDAO.deleteById(id); Assert.assertEquals(1, delete); delete = this.userBaseDAO.deleteByName(name); Assert.assertEquals(0, delete); } finally { // 清理数据 this.userBaseDAO.deleteById(id); } } }
本文作者:奔跑的蜗牛,转载请注明原文链接:https://ntopic.cn
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 易语言 —— 开山篇