mybatis与数据库访问相关的配置以及设计

mybatis不管如何NB,总是要与数据库进行打交道。通过提问的方式,逐步深入

  • 我们常用的MyBatis配置中哪些是与数据库相关?
  1. 数据源配置:
         <environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>

看到这个配置文件,第一个直觉会想到由谁读取配置文件,谁有读取了配置信息?先忽略这个疑问,跳过。直接看下面的问题

  1.配置数据源信息后,由谁来创建、管理数据源?

    根据JDBC驱动中约束的接口,Connection需要DataSource中获取

    如果自己设计,是否直接可以由工厂返回Connection?有什么好处,有什么坏处? //TODO

         没看代码前:

                            

        实际Mybatis设计,没有直接返回Connection,而返回了dataSource

    2.对于有连接池的数据源,和无连接池的数据源,我们自己会如何设计?

      流程上的区别

     职责上区别

    现在解开谜底:看实际Mybatis设计如何?

      非池化类:

看下最关键的,获得数据库连接,和我们自己写的没啥区别。简单粗暴

  private Connection doGetConnection(Properties properties) throws SQLException {
initializeDriver();
Connection connection = DriverManager.getConnection(url, properties);
configureConnection(connection);
return connection;
}

    

    池化类:

    

    池化工作分配  :

  至此,MYBABTIS对于数据源的创建以及管理结束!看下代码,池化获得连接的代码

  @Override
public Connection getConnection() throws SQLException {
return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
}
while (conn == null) { //够用就行,拿到一个就返回
synchronized (state) { //只有有连接还回来,再走这里
if (!state.idleConnections.isEmpty()) {
// Pool has available connection
conn = state.idleConnections.remove(0);
if (log.isDebugEnabled()) {
log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
}
} else { //有两种可能:1种,都在使用中,池子没满,再新建
// Pool does not have available connection
if (state.activeConnections.size() < poolMaximumActiveConnections) {
// Can create new connection //新建连接
conn = new PooledConnection(dataSource.getConnection(), this);
if (log.isDebugEnabled()) {
log.debug("Created connection " + conn.getRealHashCode() + ".");
}
} else {
// Cannot create new connection //找一个最老的,用的ArrayList,老的在ArrayList数组的前面
PooledConnection oldestActiveConnection = state.activeConnections.get(0);
long longestCheckoutTime = oldestActiveConnection.getCheckoutTime(); //借出超时,不让他做了,直接rollback。。。暴力
if (longestCheckoutTime > poolMaximumCheckoutTime) {
// Can claim overdue connection
state.claimedOverdueConnectionCount++;
state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
state.accumulatedCheckoutTime += longestCheckoutTime;
state.activeConnections.remove(oldestActiveConnection);
if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
try {
oldestActiveConnection.getRealConnection().rollback();
} catch (SQLException e) {
/*
Just log a message for debug and continue to execute the following
statement like nothing happend.
Wrap the bad connection with a new PooledConnection, this will help
to not intterupt current executing thread and give current thread a
chance to join the next competion for another valid/good database
connection. At the end of this loop, bad {@link @conn} will be set as null.
*/
log.debug("Bad connection. Could not roll back");
}
} //拿回来后,不再放到原有的PooledConnection,新建立一个。从新开始.老的REAL connection还被oldestActiveConnection引用,不会内存溢出?
conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp()); oldestActiveConnection.invalidate();
if (log.isDebugEnabled()) {
log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
}
} else {
// Must wait //大家都在用着,你只能等着了。
try {
if (!countedWait) {
state.hadToWaitCount++;
countedWait = true;
}
if (log.isDebugEnabled()) {
log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
}
long wt = System.currentTimeMillis();
state.wait(poolTimeToWait);
state.accumulatedWaitTime += System.currentTimeMillis() - wt;
} catch (InterruptedException e) {
break;
}
}
}
}
if (conn != null) {
// ping to server and check the connection is valid or not
if (conn.isValid()) {
if (!conn.getRealConnection().getAutoCommit()) {
conn.getRealConnection().rollback();
}
conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
conn.setCheckoutTimestamp(System.currentTimeMillis());
conn.setLastUsedTimestamp(System.currentTimeMillis());
state.activeConnections.add(conn);
state.requestCount++;
state.accumulatedRequestTime += System.currentTimeMillis() - t;
} else {
if (log.isDebugEnabled()) {
log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
}
state.badConnectionCount++;
localBadConnectionCount++;
conn = null; //如果累计有这些个链接失效了,则报个异常.
if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
if (log.isDebugEnabled()) {
log.debug("PooledDataSource: Could not get a good connection to the database.");
}
throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
}
}
}
} }

        

    

  

mybatis与数据库访问相关的配置以及设计的更多相关文章

  1. SpringBoot:4.SpringBoot整合Mybatis实现数据库访问

    在公司项目开发中,使用Mybatis居多.在 SpringBoot:3.SpringBoot使用Spring-data-jpa实现数据库访问 中,这种jpa风格的把sql语句和java代码放到一起,总 ...

  2. mysql+spring+mybatis实现数据库读写分离[代码配置] .

    场景:一个读数据源一个读写数据源. 原理:借助spring的[org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource] ...

  3. Spring Mvc和Mybatis的多数据库访问配置过程

    Spring Mvc 加Mybatis的多数据库访问源配置访问过程如下: 在applicationContext.xml进行配置 <?xml version="1.0" en ...

  4. Spring+MyBatis实践—MyBatis数据库访问

    关于spring整合mybatis的工程配置,已经在Spring+MyBatis实践—工程配置中全部详细列出.在此,记录一下几种通过MyBatis访问数据库的方式. 通过sqlSessionTempl ...

  5. 使用MyBatis搭建一个访问mysql数据库的简单示例

    MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用 ...

  6. Spring+MyBatis双数据库配置

    Spring+MyBatis双数据库配置 近期项目中遇到要调用其它数据库的情况.本来仅仅使用一个MySQL数据库.但随着项目内容越来越多,逻辑越来越复杂. 原来一个数据库已经不够用了,须要分库分表.所 ...

  7. Spring+Mybatis+Mysql搭建分布式数据库访问框架

    一.前言 用Java开发企业应用软件, 经常会采用Spring+MyBatis+Mysql搭建数据库框架.如果数据量很大,一个MYSQL库存储数据访问效率很低,往往会采用分库存储管理的方式.本文讲述如 ...

  8. spring配置druid连接池和监控数据库访问性能

    Druid连接池及监控在spring配置如下: <bean id="dataSource" class="com.alibaba.druid.pool.DruidD ...

  9. SpringBoot入门 (四) 数据库访问之JdbcTemplate

    本文记录在SpringBoot中使用JdbcTemplate访问数据库. 一 JDBC回顾 最早是在上学时接触的使用JDBC访问数据库,主要有以下几个步骤: 1 加载驱动 Class.forName( ...

随机推荐

  1. JAVA003-变量、数据类型

    一.变量的三个元素:变量名(房间名字).变量类型(房间的类型).变量值(入住的人). 二.变量的命名规则: 1.驼峰法     2.尽量简单,见名知意     3.长度没有限制     4.满足标志符 ...

  2. 小程序之--canvasToTempFilePath

    最近做的小程序需要图片上传头像的功能,不对上传的图片做处理肯定出来的效果不好:所以就隐藏了一个canvas对上传的图片进行压缩或者进行大小的编辑: 通过chooseImage方法,可以拿到图片的临时路 ...

  3. ELK简单安装测试

    1 介绍组件 Filebeat是一个日志文件托运工具,在你的服务器上安装客户端后,filebeat会监控日志目录或者指定的日志文件,追踪读取这些文件(追踪文件的变化,不停的读). Kafka是一种高吞 ...

  4. http协议常见状态码含义

    状态码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值: 2xx:成功--表示请求已被成功接收.理解.接受 200(成功)  服务器已成功处理了请求.通常,这表示服务器提供了请求的网页. ...

  5. java标志性接口

    标识接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情.使用标记接口的唯一目的是使得可以用instanceof进行类型查询,例如:if(obj inst ...

  6. 使用getInstance()方法的原因及作用

    使用getInstance()方法的原因及作用 先举例说明: 下面是一个例子,为什么要把这个类实例化?有什么好处? //实例化 public static DBConnect instance; pu ...

  7. 【python】闭包

    一.闭包满足的条件 闭包 = 内部函数 + 定义函数的环境 条件一 : 内部函数 条件二: 外部环境的变量 二.实战 def outer(): x = 10 y = 20 def inner(): p ...

  8. 交换排序-C#实现

    交换排序包括:冒泡排序和快速排序 具体代码如下: 冒泡排序: /// <summary> /// 冒泡排序 /// 稳定性:稳定 /// 时间复杂度:O(n2) /// </summ ...

  9. test png

    $x^2 \int $ When $a \ne 0$, there are two solutions to (ax^2 + bx + c = 0) and they are $$x = {-b \p ...

  10. win10连接宽带,拨号提示错误720:不能建立到远程计算机的连接,解决方法

    使用账号密码登录时,一直报720错误.解决方法是卸载以下IP驱动.卸载之后重新连接就正常了.亲测有效