[关闭]
@zero1036 2019-03-25T07:52:29.000000Z 字数 3671 阅读 985

mysql典型编程技巧

Mysql


数据写入

1.1 缺少记录时插入

示例一:插入多条记录

假设有一个主键为 client_id 的 clients 表,可以使用下面的语句:

复制代码代码如下:

  1. INSERT INTO clients
  2. (client_id, client_name, client_type)
  3. SELECT supplier_id, supplier_name, 'advertising'
  4. FROM suppliers
  5. WHERE not exists (select * from clients
  6. where clients.client_id = suppliers.supplier_id);

示例二:插入单条记录

复制代码代码如下:

  1. INSERT INTO clients
  2. (client_id, client_name, client_type)
  3. SELECT 10345, 'IBM', 'advertising'
  4. FROM dual
  5. WHERE not exists (select * from clients
  6. where clients.client_id = 10345);

使用 dual 做表名可以让你在 select 语句后面直接跟上要插入字段的值,即使这些值还不存在当前表中。


1.2 存在则更新、不存在则插入-saveOrUpdate操作

有账户表account,用户充值10元现金,当用户账户记录不存在插入,存在时递增10元

id user_id amount
1 c1 88.5
2 c2 12.0

当前事务事务级别为RR情况下,死锁问题分析
同类型情景分析:select for update引发死锁分析

  1. select ac from account where user_id = c3 for update;
  2. if ac == null then
  3. insert into account (user_id, amount) values (c3, 10.0)
  4. else
  5. update account set amount = 10.0 where user_id = c3
  6. end

当记录不存在时,这是并发出现两个一样的请求:

事务1 事务2 备注
select for update 上锁排他锁,但没有锁住记录
select for update
insert 事务2阻塞等待
insert 事务1触发死锁,报错:Deadlock found when trying to get lock; try restarting transaction

1.2.1 存在条件能命中唯一索引

通过insert into table () ON DUPLICATE KEY UPDATE 实现
注意:存在条件必须命中唯一索引

  1. insert into account (user_id, amount) values (c3, 10.0)
  2. ON DUPLICATE KEY UPDATE amount = amount + 10, edit_date = now()

mybatis配置示例,通过<selectKey>配置查询结果,可以返回目标字段更新后的值

  1. <insert id="saveOrUpdate" parameterType="com.***.MetricAmountDO"
  2. useGeneratedKeys="false">
  3. <selectKey keyProperty='record.metricAmount' resultType='DECIMAL' order='AFTER'>
  4. select (select metric_amount FROM suzaku_metric_amount WHERE
  5. target_customer_id = #{record.targetCustomerId}
  6. and mission_mid = #{record.missionMid}
  7. and metric_type = #{record.metricType}
  8. and cycle_begin = #{record.cycleBegin}) metric_amount
  9. from DUAL
  10. mys
  11. </selectKey>
  12. insert into metric_amount
  13. <include refid="insertSelectiveValues"></include>
  14. ON DUPLICATE KEY UPDATE
  15. ---更新支持多个字段
  16. <trim prefix="" suffix="" suffixOverrides=",">
  17. <if test="record.metricAmount != null and coverAmount == true">
  18. metric_amount = #{record.metricAmount},
  19. </if>
  20. <if test="record.metricAmount != null and coverAmount == false">
  21. metric_amount = metric_amount + #{record.metricAmount},
  22. </if>
  23. <if test="record.boundaryAmount != null">
  24. boundary_amount = #{record.boundaryAmount},
  25. </if>
  26. <if test="record.editDate != null">
  27. edit_date = #{record.editDate,jdbcType=TIMESTAMP},
  28. </if>
  29. </trim>
  30. </insert>

1.2.2 存在条件不能命中唯一索引


数据查询

2.1 分组后对组内数据排序

mysql使用策略检索数据与行内运算并行;

sqlserver由于不支持使用策略检索数据与行内运算并行,采用rom_number()over partition by语法

mysql示例:红包操作记录表,通过红包编码分组,并获得根据创建时间倒序的,组内排序编号rank

  1. select log.red_packet_id, log.phone, log.create_date, @rowNum:=@rowNum + 1,
  2. if(@redId = log.red_packet_id, @rank:=@rank + 1,@rank:=1) as rank,
  3. ##注意:这个查询条件非常重要,用于赋值@redId并作为以上if条件
  4. @redId:=log.red_packet_id
  5. from
  6. (
  7. select red_packet_id, phone, create_date from red_packet_log
  8. order by red_packet_id, create_date desc
  9. ) log,
  10. (
  11. select @rowNum:=0, @redId:=null, @rank:=0
  12. ) b
  13. //explain
  14. id select_type table partitions type possible_keys key key_len ref rows filtered Extra
  15. 1 PRIMARY <derived3> system 1 100.00
  16. 1 PRIMARY <derived2> ALL 249 100.00
  17. 3 DERIVED No tables used
  18. 2 DERIVED red_packet_log ALL 249 100.00 Using filesort

sqlserver示例:领取记录表,通过注册号分组,获得组内排序号

  1. SELECT
  2. ActivityId, RegNumber,
  3. ROW_NUMBER() over (partition by RegNumber order by RegNumber)
  4. FROM
  5. LotteryRecord
  6. WHERE
  7. ActivityId = 22

函数

if()

格式IF(Condition,A,B)
意义:当Condition为TRUE时,返回A;当Condition为FALSE时,返回B。
作用:作为条件语句使用。

应用场景:例如分组后对组内数据排序,当groupKey(正序)相等时,分组编号 + 1,否则从1重新起始。

  1. select log.red_packet_id, log.phone, log.create_date, @rowNum:=@rowNum + 1,
  2. ##当groupKey(正序)相等时,分组编号 + 1,否则从1重新起始
  3. if(@redId = log.red_packet_id, @rank:=@rank + 1,@rank:=1) as rank,
  4. @redId:=log.red_packet_id
  5. from
  6. (
  7. select red_packet_id, phone, create_date from red_packet_log
  8. order by red_packet_id, create_date desc
  9. ) log,
  10. (
  11. select @rowNum:=0, @redId:=null, @rank:=0
  12. ) b

group_concat()

adddate()

adddate(): 添加天数,示例:`UPDATE red_packet_activity SET end_date=ADDDATE(current_timestamp(),20) WHERE id='17'

ifnull()

ifnull(): 当字段为null时,替换值。注意:如果缺少对应记录时,仍然为缺少记录

例如:SELECT IFNULL(name,'lxy') FROM Customer where id = 3

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注