mybatis内置连接池创建时间
Mybatis连接池在SqlSessionFactory创建时创建,查看build方法源码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//解析xml文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
return var5;
}
var5 = this.build(parser.parse());查看parse函数源码
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//解析configuration
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
this.parseConfiguration(this.parser.evalNode("/configuration"));查看parseConfiguration源码
//解析各个标签
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
this.environmentsElement(root.evalNode(“environments”));查看environmentsElement源码
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (this.environment == null) {
this.environment = context.getStringAttribute("default");
}
Iterator var2 = context.getChildren().iterator();
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String id = child.getStringAttribute("id");
if (this.isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
//连接池创建完毕了,datasource是连接池统一的接口标准
DataSource dataSource = dsFactory.getDataSource();
Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
this.configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
这里查看DataSource源码已经跳转到javax.sql包下了
取出连接的时机
在getMapper的时候是不会从数据库连接池获取数据库连接的,在具体操作数据库调用mapper接口方法的时候才会从连接池拿连接。
断点调试
活动连接数为0
执行数据库查询语句后活动连接数为1
sqlSession关闭后归还连接,活动连接数再次为0
JNDI
-
什么是JNDI
JNDI:java naming directory interface(java命名目录接口,它是一种服务发布技术),数据源可以以服务的形式发布出去,那么哪个应用想用,就类似于客户端调用远程服务一样去调用即可(例如天气API)
-
为什么必须是web应用
往往只有tomcat/weblogic服务器中间件(客户端和服务器之间)才支持JNDI技术
事务控制
SqlSession.open函数控制事务,查看源码,参数为true则自动提交事务
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.ibatis.session;
import java.sql.Connection;
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
ctrl+H查看实现类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.ibatis.session.defaults;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
//无参构造方法默认false,手动提交事务
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
//控制事务
public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(ExecutorType execType) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(TransactionIsolationLevel level) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), level, false);
}
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return this.openSessionFromDataSource(execType, level, false);
}
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(Connection connection) {
return this.openSessionFromConnection(this.configuration.getDefaultExecutorType(), connection);
}
public SqlSession openSession(ExecutorType execType, Connection connection) {
return this.openSessionFromConnection(execType, connection);
}
public Configuration getConfiguration() {
return this.configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
DefaultSqlSession var8;
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException var13) {
autoCommit = true;
}
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var14, var14);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
return (TransactionFactory)(environment != null && environment.getTransactionFactory() != null ? environment.getTransactionFactory() : new ManagedTransactionFactory());
}
private void closeTransaction(Transaction tx) {
if (tx != null) {
try {
tx.close();
} catch (SQLException var3) {
}
}
}
}
Mybatis动态sql实现
java中自行实现
如果不适用Mybatis框架则是在dao层实现,为了满足多个查询条件一般的java动态sql语句如下
List paras = new ArrayList();
String sql = "select * from user where and";
if(username != null && username != ""){
sql += " where username = ?";
list.add(username);//查询的参数用list存储
}
java中dao实现批量删除
String[] arr = {"1","3","5","7"};//实际上应该是从前端读取的数据
String sql = "delete from user where id in (";
for(int i = 0; i < arr.length; i++){
if(i != arr.length - 1){
sql += arr[i] + ",";
} else {
sql += arr[i] + ")";
}
}
Mybatis中实现
Mybati配置文件中的动态标签(见UserMapper.xml)
-
where标签:处理SQL语句,自动添加where关键字,并去掉紧跟他后面的一个and或者or
-
if标签,test属性,判断表达式真假
-
foreach迭代标签,可以实现批量删除
多条件查询
SQL文件UserMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper标签属性namespace和接口名相同-->
<mapper namespace="com.ahu.mapper.UserMapper">
<select id="queryUser" resultType="user">
select * from user
</select>
<!--
多条件查询
标签where拼接查询的条件(自动检查,不需要加1=1,Mys)
根据pojo中的对象决定查询的条件(username和sex)
标签if对pojo的属性进行判断
属性test判断属性是否为空
-->
<!--
直接用属性名就可以如username,如果使用user.username则user是内置的属性对象,空串用''表示
SQL语句会自动加where,也会自动删除第一个and
-->
<select id="queryByWhere" resultType="user" parameterType="user">
select * from user
<where>
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>
</mapper>
查询的代码
package com.ahu.test;
import com.ahu.mapper.UserMapper;
import com.ahu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class MainTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() throws IOException {
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(is);//工厂构建的时候创建连接池
}
/**
* 查询所有用户
*/
@Test
public void testQuery(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.queryUser();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
/**
* 模糊查询
*/
@Test
public void testQueryByWhere(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User factors = new User();
// factors.setUsername("%孙%");
factors.setSex("F");
List<User> users = userMapper.queryByWhere(factors);
if(users != null && users.size() > 0){
for (User user : users) {
System.out.println(user);
}
}
sqlSession.close();
}
}
批量删除
批量删除UserMapper.xml添加的配置
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper标签属性namespace和接口名相同-->
<mapper namespace="com.ahu.mapper.UserMapper">
<select id="queryUser" resultType="user">
select <include refid="userColumn"/> from user
</select>
<!--
多条件查询
标签where拼接查询的条件(自动检查,不需要加1=1,Mys)
根据pojo中的对象决定查询的条件(username和sex)
标签if对pojo的属性进行判断
属性test判断属性是否为空
-->
<!--
直接用属性名就可以如username,如果使用user.username则user是内置的属性对象,空串用''表示
SQL语句会自动加where,也会自动删除第一个and
-->
<select id="queryByWhere" resultType="user" parameterType="user">
select * from user
<where>
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>
<!--
批量删除
参数是集合
使用迭代标签foreach,标签属性parameterType,参数的数据类型,写的是集合的泛型
迭代标签 foreach 遍历集合,固定的集合list
属性: collection 遍历容器集合
属性: open SQL开始的符号
属性: close SQL结束符号
属性: separator SQL语句参数分隔符
属性 item 遍历的容器的元素
-->
<delete id="deleteUserByList" parameterType="list">
delete from user where id in
<foreach collection="list" open="(" close=")" separator="," item="id">
#{id}
-- 取出集合元素
</foreach>
</delete>
<!--
传入数组
collection属性填array
-->
<delete id="deleteUserByArray" parameterType="int[]">
delete from user where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<!--
批量删除,传递pojo对象
-->
<delete id="deleteUserByUserVO" parameterType="UserVO">
delete from user where id in
<foreach collection="idsList" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<sql id="userColumn">
id,username,sex,birthday,address
</sql>
</mapper>
UserMapper.java
package com.ahu.mapper;
import com.ahu.pojo.User;
import com.ahu.pojo.UserVO;
import java.util.List;
public interface UserMapper {
/**
* 查询所有用户的信息
* @return
*/
List<User> queryUser();
/**
* 模糊查询
* @param userToSearch
* @return
*/
List<User> queryByWhere(User userToSearch);
/**
* 批量删除
* @param idsList 传入集合
* @return
*/
int deleteUserByList(List<Integer> idsList);
/**
* 批量删除
* @param ids 传入数组
* @return
*/
int deleteUserByArray(int[] ids);
/**
* 批量删除,传入pojo对象
* @param userVO
* @return
*/
int deleteUserByUserVO(UserVO userVO);
}
sql标签
Mybatis提供了sql标签可以代替列名
<sql id="userColumn">
id,username,sex,birthday,address
</sql>
<select id="queryUser" resultType="user">
select <include refid="userColumn"/> from user
</select>