java8
单个list 找出重复元素
public static <E> List<E> getDuplicateElements(List<E> list) {
return list.stream() // list 对应的 Stream
.collect(Collectors.toMap(e -> e, e -> 1, Integer::sum)) // 获得元素出现频率的 Map,键为元素,值为元素出现的次数
.entrySet()
.stream() // 所有 entry 对应的 Stream
.filter(e -> e.getValue() > 1) // 过滤出元素出现次数大于 1 (重复元素)的 entry
.map(Map.Entry::getKey) // 获得 entry 的键(重复元素)对应的 Stream
.collect(Collectors.toList()); // 转化为 List
}
参考:https://segmentfault.com/q/1010000008051168
分组后对元素继续处理(加和、排序等)
Map<String, TInsHiddenDangerMeasure> rectifyMeasureMap = rectifyMeasures.stream().collect(
Collectors.groupingBy(TInsHiddenDangerMeasure::getHiddenDangerReportId,
//分组后根据getUploadTime排序并取第一个元素
Collectors.collectingAndThen(Collectors.reducing((h1, h2) -> h1.getUploadTime().isAfter(h2.getUploadTime()) ? h1 : h2), Optional::get)));
处理 Non-terminating decimal expansion; no exact representable decimal result. 异常
该错误由无限小数导致的,处理如下:进行除法时设置保留小数位及进数方式
long s = 3L;
long x = 7L;
BigDecimal b = new BigDecimal(s);
BigDecimal d = new BigDecimal(x);
BigDecimal l = b.divide(d, 4, BigDecimal.ROUND_HALF_UP);
System.out.println(l);
ORACLE
DECIMAL和NUMBER
建表语句中decimal类型就是number类型,建表后类型就变成了number,方便建表脚本在其他类型的数据库中执行。
字段值长度注意
数据默认以字节存入,3个字节为一个中文字符
表名、字段名长度限制
所谓标识符,是用户自定义的关键词,比如表名、字段名、视图名、序列名、主键等,因此,数据库表名、字段名也属于标识符。标识符最大长度30字符。
varchar2限制
varchar2最大能存4000字节内容,超过的大字符内容使用clob类型。
查询关键字in 个数限制
限制在1000个以内,否则会报错
WHERE (TASK_NO IN (?,?……省略……?,?) AND FLOW_KEY IN (?,?,?) AND STATUS = ?)
### Cause: java.sql.SQLSyntaxErrorException: ORA-01795: 列表中的最大表达式数为 1000
拼接查询字段
用 ||
进行拼接,如:
SELECT l.TASK_NO,l.CURRENT_USER_NAME||'('||l.CURRENT_USER_ID ||')' CURRENT_USER_NAME FROM FLOW_LOG l ;
连表修改数据
UPDATE
DANGER_REPORT h
SET
h.AREA_CODE = (
SELECT
tsdp.PER_CODE
FROM
PERMISSION tsdp
WHERE
tsdp.PER_CODE = SUBSTR(h.CHECK_INDUSTRIAL_ZONE_CODE, 0, 8)),
h.AREA_NAME = (
SELECT
tsdp.PER_NAME
FROM
PERMISSION tsdp
WHERE
tsdp.PER_CODE = SUBSTR(h.CHECK_INDUSTRIAL_ZONE_CODE, 0, 8))
WHERE
h.AREA_CODE IS NULL
AND h.CHECK_INDUSTRIAL_ZONE_CODE IS NOT NULL AND h.TASK_NO IS NOT NULL AND h.STATUS = '1'
;
oracle分页查询的坑
工作过程中碰到的一个坑:五百多条数据创建时间相同,根据创建时间排序之后导致某几页的数据相同,要么再加上一个数据不同的字段作为排序,要么不按创建时间排序。可参考:在Oracle数据库中查询数据时,不同分页出现数据重复的问题
拆分字段内容
参考:https://blog.csdn.net/weixin_46636220/article/details/129665978
拆分的字段应该加索引
SELECT
id,
substr(
column_name,
instr( column_name, ',', 1, levels.lvl ) + 1,
instr( column_name, ',', 1, levels.lvl + 1 ) - ( instr( column_name, ',', 1, levels.lvl ) + 1 )
) AS column_name
FROM
(
SELECT
id,
',' || column_name || ',' AS column_name,
length( column_name ) - nvl( length( REPLACE ( column_name, ',' ) ), 0 ) + 1 AS cnt
FROM
table_name
) a,
(
SELECT ROWNUM AS
lvl
FROM
(
SELECT
MAX( length( column_name || ',' ) - nvl( length( REPLACE ( column_name, ',' ) ), 0 ) ) max_len
FROM
table_name
) CONNECT BY LEVEL <= max_len
) levels
WHERE
levels.lvl <= a.cnt
ORDER BY
id
Mybatis
Mybatis连子表查询分页问题
会按连表查询后的数据来进行分页,解决方式:
- 先查主表,再用mybatis的子查询,参考 https://mybatis.org/mybatis-3/sqlmap-xml.html#nested-select-for-collection
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
Mybatis-plus自动填充
mybatisplus官方文档里其实已经写得很清楚了。需要注意的是handler中所有填充字段的类型需要和setFieldValByName方法中设置值的类型一致,否则会报错。
import lombok.Data;
@Data
@TableName("")
public class DataPojo implements MetaObjectHandler {
@ApiModelProperty("创建人")
@TableField(value = "CREATE_BY", fill = FieldFill.INSERT)
private String createBy;
@ApiModelProperty("创建时间")
@TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty("更新人")
@TableField(value = "UPDATE_BY", fill = FieldFill.UPDATE)
private String updateBy;
@ApiModelProperty("更新时间")
@TableField(value = "UPDATE_TIME", fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
}
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createBy", "", metaObject);
this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
this.updateFill(metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updatePerson", "", metaObject);
this.setFieldValByName("updateDateTime", LocalDateTime.now(), metaObject);
}
}
spring家族
@Transactional失效场景
@Transactional 加于private方法, 无效
@Transactional 加于未加入接口的public方法, 再通过普通接口方法调用, 无效
@Transactional 加于接口方法, 无论下面调用的是private或public方法, 都有效
**@Transactional 加于接口方法后, 被本类普通接口方法直接调用, 无效**
@Transactional 加于接口方法后, 被本类普通接口方法通过接口调用, 有效
@Transactional 加于接口方法后, 被它类的接口方法调用, 有效
@Transactional 加于接口方法后, 被它类的私有方法调用后, 有效
参考
:https://blog.csdn.net/w1028556865/article/details/125085130
业务幂等性处理
- 场景:用户浏览器用两个页签打开同一单据,可对同一数据重复编辑,要求某种状态后不可编辑或不可回到上一个状态。
- 处理方式:前端传给后端的数据实时性已滞后,通过前端传过来的id去数据库中查询,校验编辑的状态来判断是否可继续编辑。
Freemarker
渲染数据特殊字符处理
报错:
对实体 "E" 的引用必须以 ';' 分隔符结尾。
加上 ![CDATA[ ${data} ]]
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" w:ascii="微软雅黑" w:hAnsi="微软雅黑" w:eastAsia="微软雅黑" w:cs="微软雅黑"/>
<w:color w:val="0A0A0A"/>
<w:sz w:val="20"/>
<w:szCs w:val="20"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:t>![CDATA[ ${s.no} ]]</w:t>
</w:r>
Hutool
给图片加多行水印
//获取模板图片
ClassPathResource classPathResource = new ClassPathResource("pic/templatePic.png");
InputStream blackPngIns = classPathResource.getInputStream();
Image read = ImgUtil.read(blackPngIns);
Img srcImg = Img.from(read);
//不从中心点开始写
srcImg.setPositionBaseCentre(false);
Instant pressTextNow = Instant.now();
srcImg.pressText("你好", new Color(242, 231, 174), new Font("黑体", Font.BOLD, 80), 1000, 1100, 1.0f);
srcImg.pressText("我好", new Color(242, 231, 174), new Font("黑体", Font.BOLD, 80), 1000, 1300, 1.0f);
srcImg.pressText("大家好", new Color(242, 231, 174), new Font("黑体", Font.BOLD, 80), 1000, 1500, 1.0f);
srcImg.pressText(reasonFirstLine, new Color(242, 231, 174), new Font("黑体", Font.BOLD, 80), 1000, 1700, 1.0f);
if (reason.length() > 30) {
srcImg.pressText(reasonSecondLine, new Color(242, 231, 174), new Font("黑体", Font.BOLD, 80), 1340, 1800, 1.0f);
}
srcImg.setQuality(0.5);//压缩图片
ByteArrayOutputStream os = new ByteArrayOutputStream();
//输出水印图片
srcImg.write(os);