Mybatis 分步查询
如果有下一步查询计划,resultType需要改为resultMap,(只要这张表的查询大于1就用Map)并在Map中配置下一步计划在本计划中的实体类,查询列名,下一步计划方法路径。
当然,在分步查询sql设计前后我们需要设计分步查询实体类。
<resultMap id="map6" type="Score">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
<result column="uid" property="uid"/>
<association property="student" javaType="Student" column="sid"
select="com.qxy.mapper.StudentMapper.getStudentById"/>
</resultMap>
<select id ="getScoreByUid" resultMap="map6">
select * from t_score where uid = #{id};
</select>
分步查询和JOIN哪个更好?
分步查询的延迟加载
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 true | false false (在 3.4.1 及之前的版本中默认为 true)
动态SQL实现(一个接口有多种SQL格式)
建议 看 官网 ,非常详细
分别有 if choose where set 以及 foreach 等
批量插入传参细节
parameterType中的值 java.util.List类 和 员工类 都可以使用,但是collection的值必须与@Param别名一致。
public void testAdds(){
SqlSession sqlSession = CreateSqlSession.getSqlSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
employees.add(employee1);
employees.add(employee2);
employees.add(employee3);
employees.add(employee4);
Integer i = mapper.addEmps(employees);
sqlSession.rollback();
Integer j = mapper.addEmps(employees);
sqlSession.commit();
sqlSession.close();
}
执行上述代码后,主键是从+5开始的
public void testAdds(){
SqlSession sqlSession = CreateSqlSession.getSqlSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
employees.add(employee1);
employees.add(employee2);
employees.add(employee3);
employees.add(employee4);
Integer i = mapper.addEmps(employees);
/*sqlSession.rollback();
Integer j = mapper.addEmps(employees);*/
sqlSession.commit();
sqlSession.close();
}
如果第一次插入只做回滚并提交,,第二次批量插入还是从+5开始为什么呢?因为无论事务是否被提交,只要执行过,自增值就不会被回收。
但是通过日志有一个很有意思的新报告:
Rolling back JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Returned connection 671596011 to pool.
commit后reset AutoCommit True以及 连接ID重复
首先Mybatis
Settings 为 true的默认值
- cacheEnabled
- mutipleResultSetsEnabled
- useColumnLabel
- safeResultHandlerEnabled
- useActualParamName
分页插件PageHelper
第三方工具包,帮助你更便捷实现分页查询
需要在plugin中配置
ORM思想
从数据库表映射到Java实体类
Mybatis逆向工程及其插件MybatisX
可以帮助我们生成实体类表
jdbc-mybatis
连接池的常见参数
基于线程池,一般有最大最小连接数,初始化连接,空闲连接数,超时时间,生命周期,验证查询。
线程池常见参数
核心线程,最大线程,存活时间,拒绝策略,任务队列
实现一个线程池
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
public interface SimpleThreadPool {
void execute(Runnable task);
void shutdown();
}
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.TimeUnit;
public class SimpleThreadPoolImpl implements SimpleThreadPool {
private final int corePoolSize;
private final int maximumPoolSize;
private final long keepAliveTime;
private final TimeUnit unit;
private final BlockingQueue<Runnable> workQueue;
private final RejectedExecutionHandler handler;
private final Set<Worker> workers = new HashSet<>();
public SimpleThreadPoolImpl(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
this.unit = unit;
this.workQueue = workQueue;
this.handler = handler;
}
@Override
public void execute(Runnable task) {
if (task == null) throw new NullPointerException();
synchronized (workers) {
if (workers.size() < corePoolSize) {
addWorker(task);
} else if (!workQueue.offer(task)) {
if (workers.size() < maximumPoolSize) {
addWorker(task);
} else {
handler.rejectedExecution(task, this);
}
}
}
}
private void addWorker(Runnable firstTask) {
Worker worker = new Worker(firstTask);
workers.add(worker);
worker.start();
}
@Override
public void shutdown() {
for (Worker worker : workers) {
worker.interrupt();
}
}
private class Worker extends Thread {
private Runnable firstTask;
public Worker(Runnable firstTask) {
this.firstTask = firstTask;
}
@Override
public void run() {
try {
Runnable task = firstTask;
while (task != null || !Thread.currentThread().isInterrupted()) {
if (task == null) {
task = workQueue.poll(keepAliveTime, unit);
}
if (task != null) {
task.run();
task = null;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupt status
} finally {
workers.remove(this);
}
}
}
}
public class AbortPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, SimpleThreadPool executor) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + executor.toString());
}
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class SimpleThreadPoolDemo {
public static void main(String[] args) {
// 配置参数
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 60; // 秒
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
RejectedExecutionHandler handler = new AbortPolicy();
// 创建线程池
SimpleThreadPool threadPool = new SimpleThreadPoolImpl(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
handler
);
// 提交多个任务到线程池
for (int i = 0; i < 50; i++) {
final int taskId = i;
threadPool.execute(() -> {
System.out.println("Task " + taskId + " started by " + Thread.currentThread().getName());
try {
// 模拟任务执行时间
Thread.sleep((long) (Math.random() * 5000)); // 随机睡眠0-5秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Task " + taskId + " interrupted");
}
System.out.println("Task " + taskId + " completed by " + Thread.currentThread().getName());
});
}
// 关闭线程池
threadPool.shutdown();
}
}