您现在的位置是:首页 > Java > Java提升05:数据库连接池

Java提升05:数据库连接池

2018年11月02日 Java 浏览(152) 评论(0)

简介一、事务1.事务指的一组包含许多个单一的逻辑操作,只要有一个逻辑没有执行成功,那么都算失败, 所有的数据都回归到最初的状态(回滚)。 2.为什么要有事务为了确保逻辑的成功,如银行转账。3.使用命令行方式演示事务①开启事务starttransaction;②提交事务commit;③回滚事务rol...

一、事务

    1.事务

        指的一组包含许多个单一的逻辑操作,只要有一个逻辑没有执行成功,那么都算失败, 所有的数据都回归到最初的状态(回滚)。

    2.为什么要有事务

        为了确保逻辑的成功,如银行转账。 

    3.使用命令行方式演示事务

        ①开启事务

start transaction;

        ②提交事务

commit;

        ③回滚事务

rollback ;

    4.使用代码方式演示事务

        代码里面的事务,主要是针对连接来的。
        ①关闭自动提交的设置:conn.setAutoCommit(false);
        ②提交事务:conn.commit();
        ③回滚事务:conn.rollback();

@Test
public void testTransaction(){
	
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        conn = JDBCUtil.getConn();
		
        // 连接,事务默认就是自动提交的。 关闭自动提交。
        conn.setAutoCommit(false);
		
        String sql = "update account set money = money - ? where id = ?";
        ps = conn.prepareStatement(sql);
		
        // 扣钱, 扣ID为1 的100块钱
        ps.setInt(1, 100);
        ps.setInt(2, 1);
        ps.executeUpdate();
		
        int a = 10 /0 ;
		
        // 加钱, 给ID为2 加100块钱
        ps.setInt(1, -100);
        ps.setInt(2, 2);
        ps.executeUpdate();
		
        // 成功: 提交事务。
        conn.commit();
		
    } catch (SQLException e) {
        try {
            //事变: 回滚事务
            conn.rollback();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
    e.printStackTrace();
		
    }finally {
        JDBCUtil.release(conn, ps, rs);
    }
}

    5.事务的特性

        原子性:指的是事务中包含的逻辑,不可分割。
        一致性:指的是事务执行前后,数据的完整性。
        隔离性:指的是事务在执行期间不应该受到其他事务的影响。
        持久性:指的是事务执行成功,那么数据应该持久保存到磁盘上。

    6.事务的安全隐患 

        脏读:一个事务读到另外一个事务还未提交的数据。
        不可重复读:一个事务读到了另外一个事务提交的数据 ,造成了前后两次查询结果不一致。
        幻读: 一个事务读到了另一个事务已提交的插入的数据,导致多次查询结果不一致。

    7.可串行化

        如果有一个连接的隔离级别设置为了串行化,那么谁先打开了事务,谁就有了先执行的权利,谁后打开事务,谁就只能得着,等前面的那个事务,提交或者回滚后,才能执行。但是这种隔离级别一般比较少用,容易造成性能上的问题,效率比较低。

        1) 按效率划分,从高到低

            读未提交  > 读已提交 > 可重复读 > 可串行化

        2) 按拦截程度,从高到底

            可串行化 > 可重复读 > 读已提交 > 读未提交

    8.隔离级别

        1) 读未提交

            引发问题:脏读

        2) 读已提交

            解决:脏读,引发:不可重复读

        3) 可重复读

            解决:脏读、不可重复读,未解决: 幻读

        4) 可串行化

            解决:脏读、不可重复读、幻读。

        5) MySql 默认的隔离级别是可重复读

        6) Oracle 默认的隔离级别是读已提交

    9.丢失更新

        指一个事务去修改数据库, 另一个事务也修改数据库,最后的那个事务,不管是提交还是回滚都会造成前面一个事务的数据更新丢失。
        解决丢失更新,通常有两种方法:悲观锁和乐观锁。

    10.悲观锁和乐观锁

        悲观锁:指事务在一开始就认为丢失更新一定会发生。
        乐观锁:从来不会觉得丢失更新会发生。

二、数据库连接池

    1.数据库连接池

        ①数据库的连接对象创建工作,比较消耗性能。
        ②一开始先在内存中开辟一块空间(集合),在池子里面放置多个连接对象。后面如果需要连接,直接从池子里面去。使用完毕后, 需要归还连接,以确保连接对象能循环利用。

    2.自定义数据库连接池 

public class MyDataSource implements DataSource{
	
    List <Connection> list = new ArrayList<Connection>();
	
    public MyDataSource(){
        for (int i = 0; i < 10; i++) {
            Connection conn = JDBCUtil.getConn();
            list.add(conn);
        }
    }
	
    @Override
    public Connection getConnection() throws SQLException {
        // TODO Auto-generated method stub
        if (list.size() == 0) {
            for (int i = 0; i < 5; i++) {
                Connection conn = JDBCUtil.getConn();
                list.add(conn);
            }
        }
        Connection conn = list.remove(0);
        return conn;
    }
	
    public void addBack(Connection conn) {
        list.add(conn);
    }
}

    3.自定义连接池出现的问题

        ①需要额外记住 addBack方法。
        ②单例。
        ③无法面向接口编程。 

    4.解决自定义数据库连接池出现的问题

        由于多了一个addBack 方法,所以使用这个连接池的地方,需要额外记住这个方法,并且还不能面向接口编程。要解决此问题,可以修改接口中的close方法,原来的Connection对象的close方法,是真的关闭连接,修改close方法以后,并不是真的关闭,而是归还连接对象。

    5.DBCP

        不使用配置文件

public void testDBCP01(){

    Connection conn = null;
    PreparedStatement ps = null;
    
    try {
		
        // 1.构建数据源对象
        BasicDataSource dataSource = new BasicDataSource();
        // 连的是什么类型的数据库, 访问的是哪个数据库 , 用户名, 密码。。
        // jdbc:mysql://localhost/bank 主协议:子协议 ://本地/数据库
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost/bank");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
		
        // 2.得到连接对象
        conn = dataSource.getConnection();
        String sql = "insert into account values(null , ? , ?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, "admin");
        ps.setInt(2, 1000);
		
        ps.executeUpdate();
		
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        JDBCUtil.release(conn, ps);
    }
}

        使用配置文件

Connection conn = null;
PreparedStatement ps = null;
try {
    BasicDataSourceFactory factory = new BasicDataSourceFactory();
    Properties properties = new Properties();
    InputStream is = new FileInputStream("src//dbcpconfig.properties");
    properties.load(is);
    DataSource dataSource = factory.createDataSource(properties);
			
    //2. 得到连接对象
    conn = dataSource.getConnection();
    String sql = "insert into account values(null , ? , ?)";
    ps = conn.prepareStatement(sql);
    ps.setString(1, "liangchaowei");
    ps.setInt(2, 100);
			
    ps.executeUpdate();
			
} catch (Exception e) {
    e.printStackTrace();
}finally {
    JDBCUtil.release(conn, ps);
}

    6.C3P0

        不使用配置文件方式

Connection conn = null;
PreparedStatement ps = null;
try {
    // 1. 创建datasource
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    // 2. 设置连接数据的信息
    dataSource.setDriverClass("com.mysql.jdbc.Driver");
			
    dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
    dataSource.setUser("root");
    dataSource.setPassword("root");
			
    // 2. 得到连接对象
    conn = dataSource.getConnection();
    String sql = "insert into account values(null , ? , ?)";
    ps = conn.prepareStatement(sql);
    ps.setString(1, "admi234n");
    ps.setInt(2, 103200);
			
    ps.executeUpdate();
			
} catch (Exception e) {
    e.printStackTrace();
}finally {
    JDBCUtil.release(conn, ps);
}

        使用配置文件方式

// 默认会找c3p0-config.xml 
ComboPooledDataSource dataSource = new ComboPooledDataSource();

// c3p0-config.xml
<c3p0-config>
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost/user</property>
    <property name="user">root</property>
    <property name="password">5201314mysql</property>
    
    <property name="initalPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
  </default-config>
</c3p0-config>

三、DBUtils

    1.DBUtils的作用

        只是简化了CRUD 的代码, 但是连接的创建以及获取工作不在他的考虑范围。

    2.增删改

QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
// 增加
queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
// 删除
queryRunner.update("delete from account where id = ?", 5);
// 更新
queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);

    3.查询

        直接new接口的匿名实现类

QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
 
Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){
 
    @Override
    public Account handle(ResultSet rs) throws SQLException {
        Account account = new Account();
        while(rs.next()){
            String name = rs.getString("name");
            int money = rs.getInt("money");
 
            account.setName(name);
            account.setMoney(money);
        }
        return account;
    }
  
}, 6);
System.out.println(account.toString());

        直接使用框架已经写好的实现类

// 查询单个对象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
Account account = queryRunner.query("select * from account where id = ?", 
    new BeanHandler<Account>(Account.class), 8);
 
// 查询多个对象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
List<Account> list = queryRunner.query("select * from account ",
    new BeanListHandler<Account>(Account.class));

    4.ResultSetHandler常用的实现类

        ①BeanHandler:查询到的单个数据封装成一个对象。
        ②BeanListHandler:查询到的多个数据封装 成一个List<对象>。
        ③ArrayHandler:查询到的单个数据封装成一个数组。
        ④ArrayListHandler:查询到的多个数据封装成一个集合 ,集合里面的元素是数组。
        ⑤MapHandler:查询到的单个数据封装成一个map。
        ⑥MapListHandler:查询到的多个数据封装成一个集合 ,集合里面的元素是map。 

郑重声明:

(原创博文,转载请注明来自 蒋振飞的博客!本文链接:点击我获取我的链接)

若对你有帮助,不妨扫一扫右侧的二维码打赏我一下吧 ^_^

评论区域

评论列表

智慧如你,速度抢下沙发吧 !

更多文章目录