|
直接连数据库,数据绍每次请求都新建一个连接,库连m框用完关掉。接池架介这事我干过,数据绍在早期的库连m框一个小项目里。结果就是接池架介:页面加载慢得离谱,数据库服务器CPU飙高,数据绍连接数动不动就顶到上限。库连m框后来查日志,接池架介发现大量时间花在TCP握手和认证上。数据绍一个简单的库连m框查询可能只要2毫秒,但建立连接就要30毫秒。接池架介这就是数据绍没有连接池的代价。 连接池干的库连m框事很朴素:预先创建一批连接,放在那儿备用。接池架介应用程序要访问数据库,就从池子里借一个,用完还回去,而不是真的关闭。池子会管理这些连接的生命周期——空闲太久就回收,连接断了就重建,还能控制最大并发数,防止数据库被压垮。 拿HikariCP举例。它的默认配置里,maximumPoolSize是10,minimumIdle也是10。意思是池子始终保持10个空闲连接,最多也就能借出10个。如果第11个请求来了,就得排队等。这个数字不是拍脑袋定的。数据库能承受多少连接,跟它的max_connections参数、内存、CPU都有关系。我见过有人把池子设成200,结果数据库直接拒绝新连接,因为MySQL默认才151。 连接池的配置里有个坑:connectionTimeout。默认30秒,意思是借不到连接就等30秒然后抛异常。在高并发场景下,这个值太大反而危险——请求线程全堵在等连接上,Tomcat的线程池很快就被占满,整个服务雪崩。我一般会把它调到1到2秒,快速失败比慢慢等死强。 再说ORM框架。它跟连接池不是一回事,但经常一起用。ORM的全称是对象关系映射,简单说就是把数据库的表映射成代码里的类,把行映射成对象。你写user.setName("张三"),ORM帮你生成UPDATE users SET name='张三' WHERE id=?。 Hibernate是Java里最老牌的ORM。它功能全,但学习曲线陡。一个@Entity注解背后,藏着缓存、懒加载、脏检查、事务传播一堆机制。我见过有人用Hibernate查出几万条数据,然后循环里访问关联对象,每条都触发一次SQL,这就是典型的N+1问题。日志里密密麻麻的select语句,看一眼就头疼。 MyBatis走的是另一条路。它不帮你生成SQL,SQL还是你自己写,它只负责把参数映射进去,把结果映射出来。灵活,可控,排查问题也直接。国内很多团队偏好MyBatis,原因就在这——SQL在自己手里,优化起来心里有底。但代价是写得多,简单的CRUD也得配XML或注解。 JPA是规范,Hibernate是它的实现。Spring Data JPA又在上面包了一层,你只要定义接口方法名,比如findByUsernameAndStatus,它就能自动生成查询。方便是真方便,但方法名一长就失控,findTop10ByOrderByCreateTimeDescStatusIn这种,读起来费劲,改起来更费劲。 连接池和ORM的关系,可以这么理解:ORM是翻译官,负责把对象操作翻译成SQL;连接池是后勤,负责把数据库连接管好。ORM执行SQL的时候,底层还是从连接池拿连接。所以调优的时候,两边都得看。连接池的maximumPoolSize太小,ORM再快也得排队;ORM的N+1问题不解决,连接池再大也会被瞬间借空。 我自己的习惯是:用MyBatis-Plus做单表CRUD,复杂查询手写SQL;连接池用HikariCP,maximumPoolSize根据数据库的max_connections和应用的线程数来算,一般不超过20;connectionTimeout设1秒,idleTimeout设10分钟,maxLifetime比数据库的wait_timeout小30秒。这些数字不是固定的,得看实际压测结果。 最后说个真实案例。一个电商项目,大促前压测,QPS上到500就卡。查了半天,发现是Hibernate的二级缓存和连接池抢资源。关掉二级缓存,把连接池从50降到20,QPS反而上到1200。连接不是越多越好,够用就行。数据库那边,每个连接都要占内存,上下文切换也有开销。池子太大,数据库先扛不住。 |