Skip to main content

数据持久化

盘古开发数据持久化 API 依赖 MyBatis Plus 提供。在 MyBatis 的基础上提供了强大的内置通用 Mapper CRUD 操作、支持 Lambda 表达式、内置屏蔽不通数据库方言差异的分页插件、自动填充字段值、多种主键自动生成策略、逻辑输出、乐观锁插件等。

快速 QA:可以支持兼容哪些数据库类型?
与 MyBatis Plus 一致。支持所有 JDBC 标准数据库。分页方言兼容如下数据库: mysql、oracle、db2、h2、hsql、sqlite、postgresql、sqlserver、phoenix、gauss、clickhouse、sybase、oceanbase、firebird、cubrid、goldilocks、csiidb、达梦数据库、虚谷数据库、人大金仓数据库、南大通用(华库)数据库、南大通用数据库、神通数据库、瀚高数据库。

安装相关盘古模块

<parent>
<groupId>com.gitee.pulanos.pangu</groupId>
<artifactId>pangu-parent</artifactId>
<version>latest.version.xxx</version>
<relativePath/>
</parent>

本地配置

为便于理解,本文基于本地配置的方式编写。若改为标准的Nacos配置中心模式,请参阅:配置中心章节。

spring.application.name=pangu-examples-crud

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/pangu-examples?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&useSSL=false&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root123456
mybatis-plus.mapperLocations=classpath*:/mapper/**/*.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 分页SQL方言数据库类型标识(缺省:自动识别)
pangu.jdbc.db-type=mysql

logging.level.root=INFO
logging.level.com.gitee.pulanos.pangu=INFO

生成持久化所需的模版代码

基于实践经验,我们建议使用盘古代码生成器,而不是使用 Mybatis Plus 官方生成器。关于生成代码相关内容,请参阅 《代码生成器插件》 章节,这里不再赘述。(针对每一个数据表会生成一个 *Mapper.java 文件和一个 *Entity.java 文件)

基本数据持久化操作

这里只是给出几个简单典型的操作代码,更多内容请参阅范例或阅读 Mybatis Plus 官方文档

新增

public int aInsert() {
log.info("插入数据...");
UserEntity userEntity = new UserEntity();
userEntity.setName("XC").setAge(18).setUserType("1");
int row = userMapper.insert(userEntity);
log.info("成功插入{}条数据。{}", row, userEntity);
return row;
}

修改

public void aUpdate() {
log.info("更新数据...");
//方式1
userMapper.updateById(new UserEntity().setId(1L).setName("XC2"));

//方式2
LambdaUpdateWrapper<UserEntity> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.set(UserEntity::getAge, 100);
updateWrapper.eq(UserEntity::getId, 2L);
userMapper.update(null, updateWrapper);
//方式2简写
userMapper.update(null, Wrappers.<UserEntity>lambdaUpdate().set(UserEntity::getName, "XC2").eq(UserEntity::getId, 3L));

//方式3
UserEntity userEntity = new UserEntity();
userEntity.setName("XC2");
userMapper.update(userEntity, Wrappers.<UserEntity>lambdaUpdate().eq(UserEntity::getId, 4L));
}

删除

public void aDelete() {
log.info("删除数据...");
//方式1
userMapper.deleteById(1000L);
//方式2
userMapper.deleteBatchIds(Arrays.asList(1000L, 1001L));
//方式3
userMapper.delete(Wrappers.<UserEntity>lambdaQuery().ge(UserEntity::getAge, 150));
//方式4
userMapper.deleteById(new UserEntity().setId(2000L));
}

简单查询

public void aSelect() {
log.info("查询数据...");
//方式1
UserEntity userEntity = userMapper.selectById(1L);

//方式2
UserEntity userEntity1 = userMapper.selectOne(Wrappers.<UserEntity>lambdaQuery().eq(UserEntity::getId, 1L));

//方式3
List<UserEntity> userEntities = userMapper.selectBatchIds(Arrays.asList(1L, 2L));

//方式4
Integer age = 100;
LambdaQueryWrapper<UserEntity> lambdaQueryWrapper = Wrappers.lambdaQuery();
//动态组合查询条件的简便写法
lambdaQueryWrapper.between(ObjectUtil.isNotEmpty(age), UserEntity::getAge, 1, age);
lambdaQueryWrapper.eq(UserEntity::getUserType, "1");
lambdaQueryWrapper.orderByDesc(UserEntity::getId);
List<UserEntity> userEntities1 = userMapper.selectList(lambdaQueryWrapper);

//方式5
QueryWrapper<UserEntity> queryWrapper = Wrappers.query();
queryWrapper.select("id").ge("age", 10).orderByDesc("age");
List<Long> ids = (List<Long>) (List) userMapper.selectObjs(queryWrapper);

//方式6
List<Map<String, Object>> userMaps = userMapper.selectMaps(Wrappers.<UserEntity>lambdaQuery().eq(UserEntity::getUserType, "1"));

//方式7 count
Long cnt = userMapper.selectCount(Wrappers.<UserEntity>lambdaQuery().le(UserEntity::getGmtCreate, DateUtil.date()));

//方式8 group
QueryWrapper<UserEntity> queryWrapper1 = Wrappers.query();
queryWrapper1.select("age, count(id) as cnt").groupBy("age");
List<Map<String, Object>> mapList = userMapper.selectMaps(queryWrapper1);
}

分页查询

盘古框架已经做了 Mybatis Plus 分页插件的自动装配工作,直接使用即可。无需额外配置。

基于 Mapper API 的分页查询

public void aPageQuery(){
log.info("MyBatisPlus API 分页查询数据...");
Page page = new Page<UserEntity>(1,3);
userMapper.selectPage(page, Wrappers.<UserEntity>lambdaQuery().ge(UserEntity::getAge, 10).orderByAsc(UserEntity::getId));
Console.log("总数:{}", page.getTotal());
List<UserEntity> userEntities = page.getRecords();
userEntities.forEach(System.out::println);
}

基于手工映射 SQL 的分页查询

继续阅读本文后面的 《手工编写SQL映射》 章节可以找到。

手工编写SQL映射

tip

一般来说在日常开发中我们是不需要再编写SQL代码的,Mapper API已经能满足我们的需求了。但对于一些特殊需求,我们也可以手工写SQL映射的方式来处理。如下范例演示了手工SQL查询的操作,新增、修改、删除也是同理。

public void bPageQuery(){
log.info("自定义SQL映射分页查询数据...");
Page page = new Page<UserEntity>(1,3);
Map<String, Object> params = Maps.newHashMap();
params.put("userType", "1");
List<UserEntity> userEntities = crudMapper.listUsersByPage(page, params);
Console.log("总数:{}", page.getTotal());
userEntities.forEach(System.out::println);
}

public void cPageQuery(){
log.info("自定义SQL映射分页查询数据...");
Page page = new Page<Map<String, Object>>(1,3);
String userType = "1";
List<Map<String, Object>> userMaps = crudMapper.listUserMapsByPage(page, userType);
Console.log("总数:{}", page.getTotal());
userMaps.forEach(System.out::println);
}

public void bSelect() {
log.info("自定义SQL映射查询数据...");
Map<String, Object> params = Maps.newHashMap();
params.put("userType", "1");
List<UserEntity> userEntities = crudMapper.listUsersByMap(params);
userEntities.forEach(System.out::println);
}
src/main/java/com/gitee/pulanos/pangu/showcases/crud/dao/mapper/CrudMapper.java
/**
* 提示:自定义sql手工映射大部分时候为复杂的多表联合查询的SQL,单表操作和简单的多表连接都应该统一使用mybatis plus的API
*/
@Mapper
public interface CrudMapper {

/**
* 分页查询
* @param page 分页查询对象
* @param param
* @return
*/
List<UserEntity> listUsersByPage(Page<UserEntity> page, Map<String, Object> param);

/**
* 分页查询
* @param page 分页查询对象
* @param userType
* @return
*/
List<Map<String, Object>> listUserMapsByPage(Page<Map<String, Object>> page, String userType);

/**
* 普通集合查询
* @param param
* @return
*/
List<UserEntity> listUsersByMap(Map<String, Object> param);

}
src/main/resources/mapper/CrudMapper.xml
<!-- 分页查询 -->
<select id="listUsersByPage" resultType="com.gitee.pulanos.pangu.showcases.crud.dao.entity.UserEntity">
select id,name,age,user_type,gmt_create,gmt_update from user
<where>
<if test="param.userType!=null and param.userType!=''">
user_type = #{param.userType}
</if>
</where>
ORDER BY id
</select>

<!-- 分页查询 -->
<select id="listUserMapsByPage" resultType="java.util.Map">
select age, count(id) as userCnt from user
<where>
<if test="userType!=null and userType!=''">
user_type = #{userType}
</if>
</where>
GROUP BY age
ORDER BY age DESC
</select>

<!-- 普通查询 -->
<select id="listUsersByMap" resultType="com.gitee.pulanos.pangu.showcases.crud.dao.entity.UserEntity">
select id,name,age,user_type,gmt_create,gmt_update from user
<where>
<if test="userType!=null and userType!=''">
user_type = #{userType}
</if>
</where>
</select>

高级特性

事务

单一数据源事务,直接使用 Spring 事务相关注解即可( @EnableTransactionManagement@Transactional )。对于分布式事务请参阅 《分布式事务》 章节。

字段值自动填充

Coming soon...

逻辑删除

Coming soon...

启动入口

@EnableTransactionManagement
@SpringBootApplication
public class CrudApplication {
public static void main(String[] args) {
PanGuApplicationBuilder.init(CrudApplication.class).run(args);
}
}

本文相关范例源码

下一步

继续阅读其它章节获取你想要的答案或通过我们的 开发者社区 寻求更多帮助。