entity manager未关闭造成的影响
spring jpa version:1.10.1
底层hibernate: 5.1.0
某些情况需要自行写sql,然后就用到了EntityManager, 用完之后没有显示的close(==|||)
上线后大量请求超时,偶尔有那么几个请求会快
首先确定不是数据库正在的查询慢,目前量还很小,然后找到sql去数据库查询系统确认,查询速度接近0ms
然后怀疑是网络延迟,然后找到接收到前端传递过来的参数,想让前端查查log他们发送的时间点,没人搭理…无果
找运维同学要了份error log,一看,果然不是网络问题,大量报获取不到数据库链接,等待获取连接超时,当时心一惊
想着用的spring jpa,底层使用的数据库链接应该会自动释放啊,找dba看了下应用系统连到数据库的活跃连接数,果然每个应用的连接数都到了最大值
想了想,有地方用了EntityManager,找到使用的地方一看,没有手动关闭,哎….
加上close后,问题解决…
没有任何技术含量,给自己的一个提醒,用惯了自动释放连接,以后得多注意
一个表字段叫status,值是1,2,3,4,5,6,7,8,9
project manager想进行分类,然后某一类的排序规则是按照status 1,5,3,4 排序,相同状态的按时间排序
select demo_id,status,create_time from demo_table
where userId='123456' and status in (1,5,3,4)
order by field(status,1,5,3,4), demo_id desc
limit 0,30;
+----+-------------+-----------------+------+---------------+------------+---------+-------+------+----------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------+------+---------------+------------+---------+-------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | demo_table | ref | idx_userId | idx_userId | 202 | const | 63 | 100.00 | Using index condition; Using where; Using filesort |
+----+-------------+-----------------+------+---------------+------------+---------+-------+------+----------+----------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
这种查询用到了一个函数order by field,看执行计划用到了file sort,查询了一下并不是用到了磁盘排序,而是一个排序操作
在开发环境把数据造到1000w,查询依然可以走0.0几秒完成,暂时使用这种方式,虽说大量查询可能会有性能问题,先标记一下,慢慢观察,出现性能问题使用下面的方式改写
select * from (
select * from (select demo_id,status,create_time from demo_table where userId='123456789' and status=1 order by demo_id desc) t1
union all
select * from (select demo_id,status,create_time from demo_table where userId='123456789' and status=5 order by demo_id desc) t2
union all
select * from (select demo_id,status,create_time from demo_table where userId='123456789' and status=3 order by demo_id desc) t3
union all
select * from (select demo_id,status,create_time from demo_table where userId='123456789' and status=4 order by demo_id desc) t4
) t5
limit 0,30;
+----+--------------+-----------------+------+---------------+------------+---------+-------+------+----------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-----------------+------+---------------+------------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 8 | 100.00 | NULL |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 3 | DERIVED | demo_table | ref | idx_userId | idx_userId | 202 | const | 1 | 100.00 | Using where |
| 4 | UNION | <derived5> | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 5 | DERIVED | demo_table | ref | idx_userId | idx_userId | 202 | const | 1 | 100.00 | Using where |
| 6 | UNION | <derived7> | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 7 | DERIVED | demo_table | ref | idx_userId | idx_userId | 202 | const | 1 | 100.00 | Using where |
| 8 | UNION | <derived9> | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 9 | DERIVED | demo_table | ref | idx_userId | idx_userId | 202 | const | 1 | 100.00 | Using where |
| NULL | UNION RESULT | <union2,4,6,8> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+-----------------+------+---------------+------------+---------+-------+------+----------+-----------------+
10 rows in set, 1 warning (0.00 sec)
因为要union all,所以用了临时表,同样的1000w数据,查询cost和上面基本一样
比上面麻烦的就是有多个分类组合的时候需要写多个sql
redis配置参数笔记
测试的redis版本是3.0.501
当hash里面的元素数量很少的时候,在redis里面会特殊处理,数据结构是长度预定义的,key-value对形式的线性数组
用这种方式进行处理是为了权衡cpu和内存
当entry数量很多时,才会转成使用hash-table这种数据结构存储
想开启这个特性,需要设置下面的2个参数(官方文档里面还是写的zipmap)
hash-max-ziplist-entries 256
hash-max-ziplist-value 64
entries这个参数说明是这个hash里面元素的个数,*-value是说这个hash里面的单一的value大小超过1024字节时,变成hashtable存储
test{
k1:aaagggggggggg (k1占2个字节,value占13字节)
k2:bbbbbbbbbbbbbb (k1占2个字节,value占14字节)
k3:dfgdfgdfgerterterdfgdfg (k1占2个字节,value占23字节)
k4:hhhhh (k1占2个字节,value占5字节)
k5:fghcbcvbcvbcvb (k1占2个字节,value占14字节)
k6:11111111wwwwwwwwwweeeeerrrrtttdddxcvxcvxcvxcvxvxcvxcvxcvxvxcvqopp (k1占2个字节,value占65字节)
}
先添加了k1~k5,5个entry,然后使用debug object test,查看
127.0.0.1:6379> debug object test Value at:000007EB1F54F350 refcount:1 encoding:ziplist serializedlength:130 lru:12389993 lru_seconds_idle:5
然后添加k5,value的字节数逐渐增长到65,当长度为64时,依然是ziplist结构,value大小变成65字节时,结果如下
127.0.0.1:6379> debug object test Value at:000007EB1F54F350 refcount:1 encoding:hashtable serializedlength:133 lru:12390003 lru_seconds_idle:4
参考文档
官方文档
drools when的高级语法之forall,from,collect笔记
规则如下
rule fromSyntaxRule
when
$order : OrderBOM(canContinue == true)
$par : ParticipantBOM(sex == 1) from $order.insured
then
System.out.println("result:" + $par);
end
在java代码如下
OrderBOM order = new OrderBOM();
order.setAmount("sss");
List<ParticipantBOM> list = new ArrayList<ParticipantBOM>(5);
order.setInsured(list);
for (int i = 0; i < 5; i++) {
ParticipantBOM in = new ParticipantBOM();
in.setSex(i%2);
in.setUserName(i + "");
list.add(in);
}
kieSession.insert(order);
kieSession.fireAllRules(new AgendaFilter() {
public boolean accept(Match match) {
return match.getRule().getName().equals("forallSyntaxRule");
}
});
解释:一个order对象,包含5个参与者对象,执行结果是上面的rule被执行了2次
rule collectSyntaxRule2
when
$order : OrderBOM(canContinue == true)
$li : ArrayList(size >= 3)
from collect (
ParticipantBOM(sex == 1) from $order.insured
)
then
System.out.println("collectSyntaxRule2 has at least 3 elements:" + $li.size());
end
java代码如上
解释:查找order下面的参与者列表中性别为1,且聚合后元素数量>=3时才触发规则(即执行then部分的代码)
rule collectSyntaxRule
when
$order : OrderBOM(canContinue == true)
$li : LinkedList()
from collect (
ParticipantBOM(sex == 1) from $order.insured
)
then
System.out.println("collect result:" + $li.size());
end
解释:和上面类似,但是如果把sex==2改成sex==10,则依然会触发规则(即then部分,应该是LinkedList默认是一个对象而不是null)
规则文件如下
rule forallSyntaxRule
when
$order : OrderBOM(canContinue == true)
forall(ParticipantBOM(sex == 1) from $order.insured)
then
System.out.println("forallSyntaxRule, all sex is 1");
end
这种情况是必须order下面所有的参与者对象的性别都是1时才会触发规则(即then部分的代码)
spring jpa常用查询
EntityManager em = emf.createEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<StatEntity> q = cb.createQuery(StatEntity.class);
Root<StatEntity> c = q.from(StatEntity.class);
q.multiselect(c.get("userId"), c.get("userName"),cb.count(c.get("userId")));
q.where(cb.equal(c.get("status"), 8));
q.groupBy(c.get("userId"), c.get("userName"));
Order userIdOrder = new OrderImpl(c.get("userId"), true);
Order countOrder = new OrderImpl(cb.count(c.get("userId")), false);
q.orderBy(countOrder, userIdOrder);
System.out.println("con:" + em.createQuery(q).getResultList());
CriteriaQuery
这部分创建query的时候,可以不使用entity,普通的java bean对象也可以,要有相对应的构造函数
只查询StatEntity里面的id列
@Query("select new com.illegalaccess.po.StatEntity(id) from StatEntity te " +
"where te.status=:status and te.updateTime<:updateTime and te.retryCount<:retryCount")
Page<StatEntity> findAllByTaskStatus(@Param("status") Integer status,
@Param("updateTime") Date updateTime,
@Param("retryCount") Integer retryCount,
Pageable pageable);
在StatEntity里面添加只包含id的构造函数,则查询只查询id列
若想查询id,status,则在StatEntity里面添加如下构造函数
public StatEntity(Long id, Integer status) {
this.id = id;
this.status = status;
}
上面的查询换成如下格式
@Query("select new com.illegalaccess.po.StatEntity(id,status) from StatEntity te " +
"where te.status=:status and te.updateTime<:updateTime and te.retryCount<:retryCount")
Page<StatEntity> findAllByTaskStatus(@Param("status") Integer status,
@Param("updateTime") Date updateTime,
@Param("retryCount") Integer retryCount,
Pageable pageable);
select new com.illegalaccess.po.StatEntity(id,status),这里的StatEntity也可以换成普通的java bean