0%

MySQL

安装

下载zip包

解压后,cd到对应的bin目录

初始化mysqlmysqld --initialize --console

记住输出的初始密码

shell
1
2
3
...
2018-04-20T02:35:05.464644Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: APWCY5ws&hjQ
...

安装mysqld install

启动net start mysql

连接上本机的mysqlmysql -u root -p

第一次连上改密码:

ALTER USER 'username'@'localhost' IDENTIFIED BY 'password'

参考文献

MySQL逻辑架构

MySQL逻辑架构找不到图片(Image not found)

连接管理与安全性。

当客户端(应用)连接到MySQL服务器时,服务器需要对其进行认证。一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限

优化与执行。

MySOL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化。

并发控制。

MySQL在两个层面的并发控制:服务器层存储引擎层

  • 读写锁。这两种类型的锁通常被称为共享锁(sharedlock)和排他锁(exclusivelock),也叫读锁(readlock)和写锁(write1ock)。
  • 锁粒度。
    • 表锁(table lock)。表锁是MySQL中最基本的锁策略,并且是开销最小的策略。尽管存储引擎可以管理自已的锁,MySQL本身还是会使用各种有效的表锁来实现不同的目的。例如,服务器会为诸如ALTER TABLE之类的语句使用表锁,而忽略存储引擎的锁机制。
    • 行级锁(row lock)。行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。行级锁只在存储引擎层实现,而MySQL服务器层没有实现,

事务

原子性(atomicity)

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

一致性(consistency)

数据库总是从一个一致性的状态转换到另外一个一致性的状态。一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。

隔离性(isolation)

通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外一个账户汇总程序开始运行,则其看到的支票账户的余额并没有被减去200美元。后面我们讨论隔离级别(Isolationlevel)的时候,会发现为什么我们要说“通常来说”是不可见的。

隔离级别

较低级别的隔离通常可以执行更高的并发,系统的开销也更低。

图片详情找不到图片(Image not found)
READ UNCOMMITTED(未提交读)

在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。这个级别会导致很多间题,从性能上来说,READ UNCOMMTTED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。

READ COMMITTED(提交读)

大多数数据库系统的默认隔离级别都是READ COMMITTED(但MySQL不是)。READ COMMITTED满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读(nonrepeatableread),因为两次执行同样的查询,可能会得到不一样的结果。

REPEATABLE READ(可重复读)

REPEATABLEREAD解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(PhantomRead)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multi version Concurrency Control)解决了幻读的问题。本章稍后会做进一步的讨论。

可重复读是MySQL的默认事务隔离级别。

SERIALIZABLE(可串行化)

SERALIZABLE是最高的隔离级别。它通过强制事务量行热行,避免了前面说的读的问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。

持久性(durability)

一且事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。持久性是个有点模糊的概念,因为实际上持久性也分很多不同的级别。有些持久性策略能够提供非常强的安全保障,而有些则未必。而且不可能有能做到100%的持久性保证的策略(如果数据库本身就能做到真止的持久性,那么备份又怎么能增加持久性呢?)。在后面的一些章节中,我们会继续讨论MySQL中持久性的真正含义。

死锁

优化查询性能

优化数据访问

案例解决方案
查询不需要的记录查询后面加上LIMIT
多表关联时返回全部列只取需要的列:
SELECT sakila.actor.* FROM sakila.actor...
总是取出全部列每次看到SELECT*的时候都需要用怀疑的眼光审视
重复查询相同的数据使用缓存

MySQL是否在扫描额外的记录

衡量查询开销的指标

  • 响应时间
  • 扫描的行数
  • 返回的行数

响应时间

快速上限估计法—Tapio Lahdenmaki和MikeLeach编写的Relational Database Index Design and the Optimizers

  • 了解这个查询需要哪些索引以及它的执行计划是什么,
  • 然后计算大概需要多少个顺序和随机I/O,
  • 再用其乘以在具体硬件条件下次I/O的消耗时间。
  • 最后把这些消耗都加起来,就可以获得一个大概参考值来判断当前响应时间是不是一个合理的值。

扫描的行数和返回的行数

  • 对于找出那些“糟糕”的查询,这个指标可能还不够完美,因为并不是所有的行的访代价都是相同的。较短的行的访问速度更快,内存中的行也比磁盘中的行的访问速度要快得多。
  • 理想情况下扫描的行数和返回的行数应该是相同的。

扫描的行数和访问类型

一些技巧

当mysql的表非常大的时候,count(*)非常慢怎么办

SELECT table_schema,table_name,table_rows FROM INFORMATION_SCHEMA.TABLES

SELECT table_name,table_rows FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 'your_table_name'

  • table_schema:表在哪个数据库
  • table_name:表的名字
  • table_rows:表有多少行

查询数据库某张表占的存储空间

代码详情
1
2
3
4
5

select concat(round(sum(data_length/1024/1024),2),'MB') as data_length_MB,
concat(round(sum(index_length/1024/1024),2),'MB') as index_length_MB
from information_schema.tables
where table_schema='数据库名称' AND table_name='表名称';

查看MySQL数据库一个表所占的存储空间大小

USING BTREE的意义

// TODO

mysql中key 、primary key 、unique key 与index区别

KEY idx_type (type)的意义是什么

参考文献

NOT NULL约束的意义

1
2
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

像create_time只会第一次不传的话初始化。

但update_time加ON UPDATE之后每次不传的话,在更新的时候都会自动变化。

查看建表语句

show关键字

SHOW CREATE TABLE TEST

desc关键字

desc tablename

key的意义:

1.如果键为空,则该列的值可以重复,表示该列没有索引,或者是非唯一复合索引的非前导列。

2.如果键是PRI,那么列就是主键的一个组成部分。

3.如果Key为UNI,则该列是唯一值索引的第一列(前导列),并且不能包含空值。

4.如果Key为MUL,则该列的值可以重复。此列是非唯一索引的前导列(第一列)或唯一索引的组成部分,但可以包含空值。

参考文献

从schema里面拿

代码详情
1
2
use information_schema;
select * from columns where table_name='jos_modules';

参考文献

函数

创建数据库

CREATE DATABASE database_name;

Mysql中timestamp用法详解

Mysql中timestamp用法详解

MySQL timestamp(3)问题

timestamp(3) 表示秒后3位小数,注意最多为6位。

varchar

mysql 中的 varchar 是有最大长度限制的,这个值是 65535 个字节。

最大限制

ADD

add column after

insert

一次插入多行,传统mysql语句不支持

参考文献

explain

  • ALL:表示全表扫描,性能最差。
  • index:表示基于索引的全表扫描,先扫描索引再扫描全表数据。
  • range:表示使用索引范围查询。使用>、>=、<、<=、in等等。
  • ref:表示使用非唯一索引进行单值查询。
  • eq_ref:一般情况下出现在多表join查询,表示前面表的每一个记录,都只能匹配后面表的一行结果。
  • const:表示使用主键或唯一索引做等值查询,常量查询。
  • NULL:表示不用访问表,速度最快。

range的效率会比index高

这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间了解,因为可以学习到查询是如何执行的。学会解释EXPLAIN将帮助你了解MySQL优化器是如何工作的。

当执行查询时,这个EXPLAIN标记会使其返回关于在执行计划中每一步的信息,而不是执行它。它会返回一行或多行信息,显示出执行计划中的每一部分和执行的次序。

在查询中每个表在输出中只有一行。如果查询是两个表的联接,那么输出中将有两行。

  • EXPLAIN EXTENDED看起来和正常的EXPLAIN的行为一样,但它会告诉服务器“逆向编译”执行计划为一个SELECT语句。
  • EXPLAIN PARTITIONS会显示查询将访问的分区,如果查询是基于分区表的话。它只在MySQL 5.1和更新版本中存在。

explain的限制

  • EXPLAIN根本不会告诉你触发器、存储过程或UDF会如何影响查询。
  • 它并不支持存储过程,尽管可以手动抽取查询并单独地对其进行EXPLAIN操作。
  • 它并不会告诉你MySOL在查询执行中所做的特定优化。
  • 它并不会显示关于查询的执行计划的所有信息(MySOL开发者会尽可能增加更多信息。
  • 它并不区分具有相同名学的事物。例如,它对内存排序和临时文件都使用“filesort”并且对于磁盘上和内存中的临时表都显示“Usingtemporary”。
  • 可能会误导。例如,它会对一个有着很小LIMIT的查询显示全索引扫描。(MySQL5.1的EXPLAIN关于检查的行数会显示更精确的信息,但早期版本并不考虑LIMIT。)

select查询的分类:

  • 简单查询
  • 复杂查询
    • 简单子查询
    • 所谓的派生表(在FROM子句中的子查询)
    • UNION查询

Id列

如果在语句当中没有子查询或联合,那么只会有唯一的SELECT,于是每一行在这个列中都将显示个1。否则,内层的SELECT语句一般会顺序编号,越嵌套在里面的id越值大。

UNION结果总是放在一个匿名临时表中

EXPLAIN SELECT 1 UNION ALL SELECT 1 这是什么语句

select_type 列

这一列显示了对应行是简单还是复杂SELECT

SIMPLE

意味着查询不包括子查询和UNION

PRIMARY

如果查询有任何复杂的子部分,则最外层部分标记为PRIMARY

SUBQUERY

包含在SELECT列表中的子查询中的SELECT(换句话说,不在FROM子句中)标记为SUBQUERY。

DERIVED

DERIVED值用来表示包含在FROM子句的子查询中的SELECT,MySQL会递归执行并将结果放到一个临时表中。服务器内部称其“派生表”,因为该临时表是从子查询中派生来的。

UNION

在UNION中的第二个和随后的SELECT被标记为UNION。第一个SELECT被标记就好像它以部分外香询来热行。这就是之前的例子中在UNION中的第一个SELECT显示为PRIMARY的原因。如果UNION被FROM子句中的子查询包含,那么它的第一个SELECT会被标记为DERIVED。

UNION RESULT

用来从UNION的匿名临时表检索结果的SELECT被标记为UNION RESULT

table 列

这一列显示了对应行正在访问哪个表。

想起我们在第6章中展示的左侧深度优先(left-deep)树了吗?MySQL的查询执行计划总是左侧深度优先树。如果把这个计划放倒,就能按顺序读出叶子节点,它们直接对应于EXPLAIN中的行。之前的查询计划看起来如图D-1所示。

图片详情找不到图片(Image not found)

pp.727

派生表和联合

一个复杂SELECT类型的例子

type 列

ALL

这就是人们所称的全表扫描,通常意味着MySQL必须扫描整张表,从头到尾,去找到需要的行。(这里也有个例外,例如在查询里使用了LIMIT,或者在Extra列中显示“Usingdistinct/notexists”。)

index

这个跟金表扫描一样,只是MySOL扫描表时按索引次序进行而不是行。它的主要优点是避免了排序,最大的缺点是要承担按索引次序读取整个表的开销。这通常意味着若是按随机次序访问行,开销将会非常大。

如果在Extra列中看到“Usingindex”,说明MySQL正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描的开销要少很多。

range

范围扫描就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行。这比全索引扫描好一些,因为它用不着遍历全部索引。显而易见的范围扫描是带有BETWEEN或在WHERE子句里带有>的查询。

当MySQL使用索引I去查找一系列值时,例如IN()OR列表,也会显示为范围扫描。然而,这两者其实是相当不同的访问类型,在性能上有重要的差异。更多信息可以查看第5章的文章“什么是范围条件”。此类扫描的开销跟索引类型相当。

ref

这是一种索引访问(有时也叫做索引查找),它返回所有匹配某个单个值的行。然而,它可能会找到多个符合条件的行,因此,它是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做ref是因为索引要跟某个参考值相比较。这个参考值或者是个常数,或者是来自多表查询前一个表里的结果值。

ref_or_null是ref之上的一个变体,它意味着MySQL必须在初次查找的结果里进行第二次查找以找出NULL条目。

eq_ref

使用这种索引查找,MySQL知道最多只返回一条符合条件的记录。这种访问方法可以在MySQL使用主键或者唯一性索引查找时看到,它会将它们与某个参考值做比较。MySQL对于这类访问类型的优化做得非常好,因为它知道无须估计匹配行的范围或在找到匹配行后再继续查找。

const,system

当MySQL能对查询的某部分进行优化并将其转换成一个常量时,它就会使用这些访问类型。举例来说,如果你通过将某一行的主键放入WHERE子句单的方式来选取此行的主键,MySOL就能把这个查询转换为一个常量。然后就可以高效地将表从联接执行中移除。

NULL

这种访问方式意味着MVSOL能在优化阶段分解查询语句,在执行阶段基至用不着再访问表或者索引。例如,从一个索引列里选取最小值可以通过单独查找索引来完成,不需要在执行时访问表。

possible_keys 列

这一列显示了查询可以使用哪些索引,这是基于查询访同的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。

key 列

这一列显示了MySQL决定采用哪个索引来优化对该表的访问。如果该索引没有出现在possible_keys列中,那么MySQL选用它是出于另外的原因一一例如,它可能选择了一个覆盖索引,哪怕没有WHERE子句。

换句话说,possible_keys揭示了哪一个索引能有助于高效地行查找,而key显示的是优化采用哪一个索引可以最小化查询成本(更多详情请参阅第6章中关于优化的成本度量值)。下面就是一个例子。

key_len 列

该列显示了MySQL在索引里使用的字节数。如果MySQL正在使用的只是索引里的某些列,那么就可以用这个值来算出具体是哪些列。要记住,MySQL5.5及之前版本只能使用索引的最左前缀。

key_len通过查找表的定义而被计算出,而不是表中的数据。

ref 列

这一列显示了之前的表在key列记录的索引中香找值所用的列或常量。下面是一个展示关联条件和别名组合的例子。

rows 列

这一列是MySQL估计为了找到所需的行而要读取的行数。这个数字是内嵌循环关联计划里的循环数目。也就是说它不是MySOL认为它最终要从表重读取出来的行数,而是MySQL为了找到符合查询的每一点上标准的那些行而必须读取的行的平均数。

要记住这个数字是MySQL认为它要检查的行数,而不是结果集里的行数。同时也要认识到有很多优化手段,例如关联缓冲区和缓存,无法影响到行数的显示。MySQL可能不必真的读所有它估计到的行,它也不知道任何关于操作系统或硬件缓存的信息。

filtered 列

这一列是在MySQL5.1里新加进去的,在使用EXPLAIN EXTENDED时出现。它显示的是针对表单符合某个条件(WHERE子句或联接条件)的记录数的百分比所做的一入悲观估算。

Extra 列

“Using index”:此值表示MySQL将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。

“Using where”:这意味着MySQL服务器将在存储引擎检索行后再进行过滤。许多WHERE条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带wHERE子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。

“Using temporary”:这意味着MySQL在对查询结果排序时会使用一个临时表。

“Using filesort”:这意味着MySQL会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。MySOL有两种文件排序算法,你可以在第6章读到相关内容。两种方式都可以在内存或磁盘上完成。EXPLAIN不会告诉你MySQL将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。

“Range checked for each record (index map: N)”:这个值意味着没有好用的索引,新的索引将在联接的每一行上重新估算。N是显示在possible_keys列中素引的位图,并且是亢余的。

参考文献

select查询

子查询

代码详情
1
2
3
4
5
select name,age 
from person
where age > ( select age
from person
where name = '张三');

参考文献

tinyint(1)和tinyint(4)的区别和用法

参考文献

tinyint(1) 和 tinyint(4) 中的1和4并不表示存储长度,只有字段指定zerofill是有用,

mysql单引号和双引号、反引号(`)的使用

反引号:表名和字段名都用反引号引起来用来区分MYSQL的保留字与普通字符。

单引号双引号:MySQL里引用字符串时需要用一对英文单引号或英文双引号将字符串常量括起来。

MySQL 中的单引号、双引号、反引号

Mysql 中反引号 ( ` )作用

json解析

你可以使用 JSON_EXTRACT() 函数在MySQL中从JSON字符串中提取key值。语法如下:

1
JSON_EXTRACT(json_doc, path)
  • json_doc 是包含JSON字符串的列或字段
  • path 是你要提取的JSON对象的路径

例子:

假设你有一个名为 Details 的列,它包括如下的JSON字符串:

1
2
3
4
5
{
"FirstName": "John",
"LastName": "Doe",
"Email": "john.doe@example.com",
}

要提取 Email 的值,可以使用如下的SQL命令:

1
SELECT JSON_EXTRACT(Details, '$.Email') as Email FROM  table_name;

上述命令会返回:”john.doe@example.com”.

如果你想直接获取没有双引号的纯字符串,可以使用->>操作符。例如:

1
SELECT Details->>'$.Email' as Email FROM table_name;

这会直接返回: john.doe@example.com ,不带双引号。

Mybatis

foreach的时候判断条件insert

在使用 MyBatis 时,你可以使用 if 元素来进行条件插入。以下是一个示例:

1
2
3
4
5
6
7
8
9
10
<insert id="table">
insert into table (`id`, `b`,`status`)
<trim prefix="values" prefixOverrides=",">
<foreach collection="list" item="param">
<if test="param.currentStatus == param.status">
(#{param.id}, #{param.b}, #{param.status}),
</if>
</foreach>
</trim>
</insert>

在这个示例中,我使用了 if 元素来检查 param.currentStatus 是否等于 someValue。只有当该条件为真时,才会执行插入操作。同时,为了确保生成的 SQL 语句不会以逗号结尾,我在代码中添加了一个 trim 元素来移除多余的逗号。

sql与include标签<include refid=“baseColumnList“/>

参考文献

true as QUERYID的作用

预计是因为selectByPrimaryKeyQueryId这个api的目的是为了能够快速排查问题,可以传一个queryId的东西,到时候方便搜db的日志。但是如果不传的话默认是true?

csdn

接口总结

stackoverflow

updateByPrimaryKeySelective

updateByPrimaryKeySelective:只是更新新的model中不为空的字段。(注意是新的Model)

updateByPrimaryKey:则会将为空的字段在数据库中置为NULL。(在新的mode中没有set的,都会置为null)

insert和insertSelective区别

参考文献

Mysql支持表情的字符集

参考文献

MySQL单引号和双引号的区别

参考文献

[ 42000 ] [ 1101 ] BLOB/TEXT column ‘variable’ can’t have a default value

Why can’t a text column have a default value in MySQL?

timestamp转day group by

对不起,我犯了个错误。你说得对。当我们对某个表达式(如DATE_FORMAT(your_timestamp_column, ‘%Y-%m-%d’))进行GROUP BY操作时,我们必须在GROUP BY语句中使用相同的表达式,而不是别名。所以,你的查询应该是这样的:

1
2
3
4
5
6
7
SELECT 
DATE_FORMAT(your_timestamp_column, '%Y-%m-%d') as formatted_date,
COUNT(*)
FROM
your_table_name
GROUP BY
DATE_FORMAT(your_timestamp_column, '%Y-%m-%d');

这个查询将对your_timestamp_column进行按日期格式化,然后按照这个格式化的日期进行分组,并计算每一组的数量。谢谢你的纠正,很感谢!

mybatis的mapper必须要加@Param标明参数名?

SHOW INDEX 详细讲解

  • cardinality
  • 索引的基数。这是一个估算值,表示索引中唯一值的数量。这个值对于查询优化器选择索引非常重要。

拼接字符串

SELECT GROUP_CONCAT(DISTINCT name SEPARATOR ', ') AS names FROM my_table;

经验

当order by中有计算式时,order by会先于where执行?导致如果所有字段unsign减出来是负数的话,会报错

Data truncation: BIGINT UNSIGNED value is out of range in

timestamp

UNIX_TIMESTAMP() :若无参数调用,则返回一个 Unix timestamp (‘1970-01-01 00:00:00’ GMT 之后的秒数,10位) 作为无符号整数,得到当前时间戳

如果你要查当天的不需要将其转成timestamp,直接使用日期字符串或者DATE函数

正确的查询方式:select count(*) from ivr_send_info where create_time > DATE(NOW()) and create_time < DATE(DATE_ADD(NOW(), INTERVAL 1 DAY));

错误的查询方式:select count(*) from ivr_send_info where create_time > UNIX_TIMESTAMP(DATE(NOW())) and create_time < UNIX_TIMESTAMP(DATE(DATE_ADD(NOW(), INTERVAL 1 DAY)));

生产上mysql的行数

三层B+树可以存储两千万左右条

网上常说mysql单表2kw就需要考虑分表了,但生产中我们也用过2亿的表,而且毫无压力

索引长度对存储的影响?性能的影响

参考文献

一个查询多个查询字段,使用到同一个表达多次,mysql会如何处理

新增字段

ALTER TABLE table_name ADD COLUMN column_name VARCHAR(100) DEFAULT NULL COMMENT '新加字段' AFTER old_column;

删除字段

代码详情
1
2
3
ALTER TABLE student
MODIFY COLUMN first_name VARCHAR(100) NOT NULL
COMMENT '这是一个新的注释';

修改字段

加索引

alter table employee add index emp_name (name);

ALTER TABLE table_name DROP field_name;

left join写三次会发生什么

改变某张表的字符集

ALTER TABLE table_name CONVERT TO CHARACTER SET charset_name;

对象嵌套list子对象,一个SQL解决

VO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.goodjob.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;

@Data
@ApiModel("实例展示")
public class XxxTableVO {

@ApiModelProperty(value = "A")
private String A;

@ApiModelProperty(value = "B")
private String B;

@ApiModelProperty(value = "C")
private String C;

@ApiModelProperty(value = "D")
private String D;

@ApiModelProperty(value = "list")
private List<DetailsVO> list;


@Data
@ApiModel("DetailsVO")
public static class DetailsVO {

@ApiModelProperty(value = "E")
private String E;

@ApiModelProperty(value = "F")
private String F;
}
}




SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<select id="executeDetails" resultMap="executeDetailsMap">
SELECT
t1.a AS A,
t1.b AS B,
t1.c AS C,
t1.d AS D,
t2.e AS E,
t2.f AS F
FROM xxxTable AS t1
INNER JOIN xxxDetails AS t2 ON t2.id = t1.details_id
WHERE t2.id = #{Id}
ORDER BY t2.id DESC
</select>
<resultMap id="executeDetailsMap" type="com.goodjob.vo.XxxTableVO">
<result column="A" property="A"/>
<result column="B" property="B"/>
<result column="C" property="C"/>
<result column="D" property="D"/>
<collection property="list" javaType="java.util.ArrayList"
ofType="com.goodjob.vo.XxxTableVO$DetailsVO">
// 注意的一点 如果子集里数据重复他会合并
<result column="E" property="E"/>
<result column="F" property="F"/>
</collection>
</resultMap>