Live2D
复制代码

07-Mybatis的核心配置和数据库连接池

1、核心配置文件中配置数据库相关属性

1.1 核心配置文件的环境配置代码如下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!--environments是环境配置,是复数说明下面可以配置多个环境
        所以default属性的值表示这个配置文件用下面的哪一套数据库配置信息
        这里使用development1
    -->
    <environments default="development1">
        
        <!--第一套数据库连接信息配置,唯一标识id叫development-->
        <environment id="development1">
            
            <!--transactionManager:表示mybatis提交事务和回滚事务的方式
			type:事务的处理类型:
			1、填JDBC 表示mybatis底层是调用JDBC规范中的Connection对象进行事务提交与回滚的
			2、填MANAGED 表示mybatis把事务委托给其他容器处理(一个服务器软件,或者是一个框架(spring))
			-->
            <transactionManager type="JDBC"/>
            
            <!--dataSource:表示使用的数据源类型,Java中,实现了javax.sql.DataSource接口
				的都可以当作数据源,数据源就是Connection对象
				type:指定数据源类型
				POOLED:表示mybatis到连接池中获取Connection对象,即使用连接池,创建PooledDataSource类对					象					
				UNPOOLED:不使用连接池,mybatis每次执行sql语句,创建一个Connection对象,执行完后将						Connection对象释放,mybatis创建的是UnPooledDataSource类对象
				JNDI:是一个java命名和目录(相当于Windows注册表,了解就好)
-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
       
    <mappers>
        <!--这里也可以添加多个sql映射文件,因为项目中不止一个表
            这就是映射文件中namespace属性的作用了-->
        <!-- <mapper resource="StudentDao.xml"/>-->
        <mapper resource="com/studymyself/dao/UserDao.xml"/>
    </mappers>
</configuration>

2、mybatis中的数据源和连接池

上面的核心配置文件中,数据源的选择类型有三种,其中前两种需要我们掌握
--连接池
	mybatis中实现了javax.sql.DataSource规范,该规范中有许多获取Connection对象的方法,有两个实现类:
	PooledDataSource和UnPooledDataSource
	其中实现类PooledDataSource是可以创建多个Connection对象,以队列的形式存到集合中,先存先被取出。当一个线程需要连接对象使直接从该集合中取出最先存的一个,另一个线程需要时又取出第二存进去的一个,线程结束后将这个连接对象放回集合中,排到后面。这个集合就是线程池,而且是线程安全的,不允许一个Connection对象被两个线程获取。
	--这种数据源的方式是实际开发中使用的,极大的减少了获取连接对象的时间
	实现类UnPooledPooledDataSource,该类中的方法是在需要的时候获取创建Connection对象,完成线程任务后释放掉。一般开发中我们只是在测试阶段使用。
实现类PooledDataSource代码片段
public class PooledDataSource implements DataSource {
    private static final Log log = LogFactory.getLog(PooledDataSource.class);
    private final PoolState state = new PoolState(this);
    private final UnpooledDataSource dataSource;
    protected int poolMaximumActiveConnections = 10;
    protected int poolMaximumIdleConnections = 5;
    protected int poolMaximumCheckoutTime = 20000;
    protected int poolTimeToWait = 20000;
    protected int poolMaximumLocalBadConnectionTolerance = 3;
    protected String poolPingQuery = "NO PING QUERY SET";
    protected boolean poolPingEnabled;
    protected int poolPingConnectionsNotUsedFor;
    private int expectedConnectionTypeCode;

    public PooledDataSource() {
        this.dataSource = new UnpooledDataSource();
    }

    public PooledDataSource(UnpooledDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public PooledDataSource(String driver, String url, String username, String password) {
        this.dataSource = new UnpooledDataSource(driver, url, username, password);
        this.expectedConnectionTypeCode = this.assembleConnectionTypeCode(this.dataSource.getUrl(), this.dataSource.getUsername(), this.dataSource.getPassword());
    }

    public PooledDataSource(String driver, String url, Properties driverProperties) {
        this.dataSource = new UnpooledDataSource(driver, url, driverProperties);
        this.expectedConnectionTypeCode = this.assembleConnectionTypeCode(this.dataSource.getUrl(), this.dataSource.getUsername(), this.dataSource.getPassword());
    }

    public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
        this.dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
        this.expectedConnectionTypeCode = this.assembleConnectionTypeCode(this.dataSource.getUrl(), this.dataSource.getUsername(), this.dataSource.getPassword());
    }

    public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
        this.dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties);
        this.expectedConnectionTypeCode = this.assembleConnectionTypeCode(this.dataSource.getUrl(), this.dataSource.getUsername(), this.dataSource.getPassword());
    }

    public Connection getConnection() throws SQLException {
        return this.popConnection(this.dataSource.getUsername(), this.dataSource.getPassword()).getProxyConnection();
    }

    public Connection getConnection(String username, String password) throws SQLException {
        return this.popConnection(username, password).getProxyConnection();
    }
    ...
实现类UnPooledPooledDataSource代码片段
public class UnpooledDataSource implements DataSource {
    private ClassLoader driverClassLoader;
    private Properties driverProperties;
    private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap();
    private String driver;
    private String url;
    private String username;
    private String password;
    private Boolean autoCommit;
    private Integer defaultTransactionIsolationLevel;
    private Integer defaultNetworkTimeout;

    public UnpooledDataSource() {
    }

    public UnpooledDataSource(String driver, String url, String username, String password) {
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public UnpooledDataSource(String driver, String url, Properties driverProperties) {
        this.driver = driver;
        this.url = url;
        this.driverProperties = driverProperties;
    }

    public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
        this.driverClassLoader = driverClassLoader;
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
        this.driverClassLoader = driverClassLoader;
        this.driver = driver;
        this.url = url;
        this.driverProperties = driverProperties;
    }

    public Connection getConnection() throws SQLException {
        return this.doGetConnection(this.username, this.password);
    }

    public Connection getConnection(String username, String password) throws SQLException {
        return this.doGetConnection(username, password);
    }
    ...

3、数据库连接池和connection的理解

数据库连接池Data Source Pool的理解

1.数据库连接池允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个连接,避免了每个方法里new connection的耗费资源和时间。

2.数据库连接池是在项目启动时候初始化的,以方便程序运行时,随时可以调用这些已经被创建好的connection。只需要getConnection()就好。

connection的建立、断开都由连接池自身来管理。

3.创建connection是个很耗时的操作,所以建议在项目启动的时候去创建connection。避免在方法里需要connection时再去new一个connection是很耗费时间的。

4.数据库连接池,怎样归还connection?
Connection connection = pool.getConnection();
pool.release(connection);//归还资源

5.程序启动时候,是怎样初始化一个数据连接池的?

答:spring启动会自动ioc注入bean,相当于new已经配置好的连接池类。连接池类里面声明了static的list,用以装放connection。然后通过static代码块来将conection add进这个list。这样,整个list就在new bean的时候,在加载这个连接池类的时,就先创建好了。后期程序运行时候,那些connection就已经存在了。

connection的理解

1.jdbc connection就是一个连接数据库的TCP实例。

2.connection是个长连接的TCP。不像hTTP是个短连接的,每次都要3次握手才能建立。

3.connection长连接是提高了性能。不过还有一些细节的问题需要解决,即mysql发现一个链接长时间没有执行查询请求,就会自动断掉这个连接。

4.具体多长时间后断掉,有个timeout设置时间。通过sql:"show global variables like '%timeout';" 查看。

当链接已经失效了,仍然去执行查询操作,一个明显的表现形式就是提示:MySQL server has gone away

5.数据库连接池通过心跳机制,每间断一段时间发送空数据包来保持维护connection存活的。

6.长连接适用于要进行大量数据传输的情况,如:数据库,redis,memcached等要求快速,数据量大的情况下。

7.我们平常用的数据库连接都是长连接的,因为我们每次都是从数据库连接池中去拿connection的!!!db source里都是长连接!!

8.mysql默认的connection timeout时间是8小时。这个可以通过my.ini配置文件修改。

9.connection不是线程安全的!Connection不是线程安全的,它在多线程环境中使用时,会导致数据操作的错乱,特别是有事务的情况.connection.commit()方法就是提交事务,你
可以想象,在多线程环境中,线程A开启了事务,然后线程B却意外的commit,这该是个多么纠结的情况.

10.多个线程同用一个connection会不会提高效率,减少多次连接的消耗?答:不会,因为connection里,每个方法都是synchronized,都执行了同步。所以并不会提高效率。
如:
public int executeUpdate(){
synchronized(connection){
//do
}
}

11.菜鸟一般都是两种方法使用connection:1。要么就是只用一个connection,多个线程都用一个connection。2.要么就是每个方法里面创建一个connection,每次调用都创建

一个connection。
这两种都是效率低下的。
因为TCP链接的创建开支是昂贵的,当然DB server所能承载的TCP并发连接数也是有限制的.因此每次调用都创建一个Connection,这是不现实的;所以才有了数据库连接池的出现.

创建一个数据库连接池:

public class SimplePoolDemo {
    //创建一个连接池
    private static LinkedList<Connection> pool = new LinkedList<Connection>(); 
    
    //初始化10个连接
    static{
        try {
            for (int i = 0; i < 10; i++) {
                Connection conn = DBUtils.getConnection();//得到一个连接
                pool.add(conn);
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError("数据库连接失败,请检查配置");
        }
    }
    //从池中获取一个连接
    public static Connection getConnectionFromPool(){
        return pool.removeFirst();//移除一个连接对象
    }
    //释放资源
    public static void release(Connection conn){
        pool.addLast(conn);
    }
}

4、指定多个mapper文件

当我们一个项目中需要的mapper文件很多时,在标签中添加太多的标签来指定各个接口的映射文件非常繁琐,所以我们可以直接指定这些mapper文件的包名,就可直接将包下的mapper文件全部配置到mybatis中了,具体实现和要求如下所示:
posted @ 2021-08-09 22:23  Milen-jie  阅读(955)  评论(0编辑  收藏  举报