mysql&mybatis,在开发中遇到的坑
Mybatis
动态拼接
数据更新,replace/insert
mybatis批量插入
插入的内容含英文单引号
Mysql
常见错误
分区表
mysql作为开源的数据库软件,好用免费,是关系型数据库的首选。我在使用的过程中,遇到的一些问题,进行汇总,不定期更新。作为记录,下次也有一个查询的地方。
Mybatis
动态拼接,实现有条件的数据更新或者插入
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.datacenter.manage.rmdbrecord.dao.OperaDataLoadMapper">
<select id="list" parameterType="***Dto" resultType="***Dto">
select
id
***
,jdbc_name AS jdbcName
from operational_data_source_mysql
where 1=1 and table_schema not in ('mysql','performance_schema','sys')
<trim>
<if test="jdbcName != null">
and jdbc_name like '%${jdbcName}%'
</if>
<if test="tableSchema != null">
and table_schema like '%${tableSchema}%'
</if>
</trim>
</select>
通过if判断,来检查test条件是否满足。如果满足则执行,不满足则跳过。而trim另外的三个参数。prefix为拼接sql的前缀,suffix这个是动态sql的后缀,suffixOverrides去掉最后多出来的符号。如:insert数据时,在对象没有数据时实现不插入的动态拼接。
数据更新(insert into...on duplicate key update 与replace into)
insert into ... on duplicate key update
在primary key或者unique key冲突的时候才会执行update之后的语句(一个有意义的index是否重要)。如:
<insert id="insert" param.....>
insert into tb1 (id,name,age) select id,name,age from tb2
on duplicate key update name=#{name},age={age}
</insert>
replace into
在唯一性冲突时(同上,primary key/unique key),将覆盖原有的数据(先删除,再插入)。这样的代价就是: 历史数据无保存、无痕迹,新数据插入(部分字段无内容,则以默认值取代。以及create_time/modify_time都是最新的。)
<insert id="insert" param...>
replace into tb1 (id,name,age)
select id,name,age
from tb2
</insert>
mybatis批量插入
对于List类型来说,我们需要批量的进行数据插入。在mysql中也类似于动态拼接sql的过程。mybatis提供了for-each方法,如:
<insert id="insertMap" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" separator=";">
insert into param_map ( file_path,type, `key`, content_line, parse_result)
values
(
substring(#{item.filePath},1,1000)
,substring((#{item.key},1,1000)
,substring(#{item.contentLine},1,1000)
,substring(#{item.parseResult},1,1000)
) on duplicate key update content_line=substring(#{item.contentLine},1,1000) ,parse_result=substring(replace(replace(#{item.parseResult},1,1000) ,mtime=now()
</foreach>
</insert>
mybatis中插入的内容中带有英文单引号
mybatis对于参数的传递有两种模式。一种是#{},一种{}则为直接传递数据。
我在遇到这个问题的时候,我是将原始的数据中''给替换掉。
mysql上的操作
脚本执行报错
-
Exception: Data too long for column
字段长度问题,可以通过将长度设置的更长,如varchar(1000),如果字段内容更长,则可以考虑设置为: mediumtext
-
Exception: Row ** was cut by GROUP_CONCAT()
处理行转列的数据处理时需呀用到group_concat函数,如果需要合并的行太多,就会报这样的错误。可以设置相关参数
//会话级 SET SESSION group_concat_max_len = 102400; //全局 SET GLOBAL group_concat_max_len=102400;
分区表
-
分区类型
序号 分区类型 说明 使用频率 1 RANGE分区 给定一个连续区间的列值(非离散),将多行数据分配给对应分区 较多 2 HASH分区 对给定的列/值算出对应的hash值,作为对应行的分区 较多 3 LIST分区 对行记录,匹配List(离散列表)值,放入指定分区 一般 4 KEY分区 类似于分桶,指定分桶数和分桶字段。有mysql内部分区 一般 -
创建
create table test.user_test(
id int comment '自增id',
phone varchar(255) comment '送检的手机号',
p_dt DATE comment '分区字段(yyyy-mm-dd)',
PRIMARY key(id,p_dt)
) ENGINE=InnoDB COMMENT='用户风险等级 - 依赖于腾讯天御接口'
PARTITION by range(TO_DAYS(p_dt))
(
PARTITION p1 VALUES LESS THAN (to_days('2019-08-12')) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (to_days('2019-08-13')) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (to_days('2019-08-14')) ENGINE = InnoDB,
PARTITION p4 VALUES LESS THAN (to_days('2019-08-15')) ENGINE = InnoDB
)
;
- 查询分区
select table_catalog,table_schema,table_name,partition_name,partition_ordinal_position,partition_method,partition_expression,table_rows,create_time,nodegroup
from information_schema.partitions
where table_schema = schema()
and table_name='user_test';
- 操作分区
-- 新增分区
alter table xqlm_base.user_test add partition (partition p4 values less than (to_days('2019-08-16')))
-- 修改分区
alter table xqlm_base.user_test PARTITION by range(TO_DAYS(p_dt)) (partition p4 values less than (to_days('2019-08-16')))
-- 重建分区
ALTER TABLE xqlm_base.user_test rebuild partitionp1,p2;
-- 优化分区
ALTER TABLE xqlm_base.user_test optimize partition p1,p2;
- 分区问题
-- 需求场景1:创建分区,类似实现create ... if exists 功能
储存过程,调度,判断