JavaWeb笔记-18-事务、隔离级别、连接池(DBCP、C3P0)、JNDI

1、事务


事务的四大特性:
1)原子性: 事务中所有操作都是不可分割的原子单位。

2)一致性: 事务执行后,数据库连接状态和业务数据规则保持一致。

3)隔离性: 在并发操作中,不同数据之间应该隔离开。

4)持久性: (备份)
        事务一旦提交,事务中所有数据操作都必须持久化到数据库中,
        就算数据库突然崩溃,也能在重启后回复数据。

mysql中的事务

将不可分割的sql语句设为事务。

背景:在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。
    如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。

开启事务:1)start transaction;

结束事务:1)commit   //结束事务
      2)rollback。  //回滚事务,重新开始操作,一般用于操作失败时。

开启事务 -> 关闭事务
这里写图片描述

jdbc中的事务

jdbc通过Connection处理事务
同一事务中所有的操作,都在使用同一个Connection对象!

Connection与事务相关的三个方法:

    setAutoCommit(boolean):设置是否为自动提交事务,
            true(默认):表示自动提交,也就是每条执行的SQL语句都是一个单独的事务。
            false:开启事务。con.setAutoCommit(false)。
    commit():结束事务。  con.commit();
    rollback():回滚事务。 con.rollback();

jdbc处理事务的代码格式:
try {
  con.setAutoCommit(false);//开启事务…
  ….
  …
  con.commit();//try的最后提交事务
} catch() {
  con.rollback();//回滚事务
}

2、事务隔离级别:


1.并发事务问题:包括三种读问题,两种更新问题。

事务的并发读问题:

1)脏读:读到另一个事务未提交数据

2)不可重复读:对同一记录的两次读取不一致。因为另一事务对该记录做了修改

3)幻读(虚读):对同一表两次查询不一致。

四大隔离级别:

防止三种并发读问题。
    1)SERIALIZABLE(串行化)
        不会出现任何并发问题。
        性能最差

    2)REPEATABLE READ(可重复读)
        防止脏读和不可重复读。
        mysql默认隔离级别

    3)READ COMMITTED(读已提交数据)oracle
        防止脏读
        oracle默认隔离级别

    4)READ UNCOMMITTED(读未提交数据)
        未做隔离,任何事务并发问题都可能出现。
        性能最好

性能:4 > 3 > 2 > 1

查看及设置隔离级别

mysql查看数据库隔离级别语句
    SELECT @@TX_ISOLATION

set transaction isolationlevel [4选一]

JDBC设置隔离级别语句
con. setTransactionIsolation(int level)

参数可选值如下:
    Connection.TRANSACTION_READ_UNCOMMITTED;
    Connection.TRANSACTION_READ_COMMITTED;
    Connection.TRANSACTION_REPEATABLE_READ;
    Connection.TRANSACTION_SERIALIZABLE。

3、事务演示


public class Transaction {
    /**
     * 转账方法
     * 
     * @param from
     *            金钱来源
     * @param to
     *            金钱去处
     * @param money
     *            交易金额
     * @throws Exception
     */
    public void transaction(String from, String to, double money) {
        // jdbc对事务操作需要使用Connection
        Connection con = null;
        try {
            con = JdbcUtils.getConnection();
            // 开启事务
            con.setAutoCommit(false);

            // 创建操作对象 AccountDao
            AccountDao dao = new AccountDao();

            // 转账操作
            dao.updateBalance(con, from, -money); // 给from减去相应金额
            dao.updateBalance(con, to, money); // 给to加上相应金额

            // 提交事务
            con.commit();
            con.close();
        } catch (Exception e) {
            // 回滚事务
            try {
                con.rollback();
                con.close();
            } catch (SQLException e1) {
            }
            throw new RuntimeException(e);
        }
    }

    //测试事务
    @Test
    public void fun1() {
        transaction("zs", "ls", 100);
    }
}
public class AccountDao {
    /**
     * 在sql处修改指定用户的余额
     * @param name
     * @param balance
     * @throws Exception 
     */
    public void updateBalance(Connection con,String name, double balance) throws Exception{
        PreparedStatement pstmt = null;
        try{

            //给pstmt设置sql模板
            String sql = "update account set balance=balance+? where name=?";
            pstmt = con.prepareStatement(sql);

            //对参数设值
            pstmt.setDouble(1,balance);
            pstmt.setString(2, name);

            //执行
            pstmt.executeUpdate();
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}

4、数据库连接池:


作用:用池来管理 Connection,达到重复使用Connection的目的。

实现接口
连接池必须实现:javax.sql.DataSource接口!

池参数(所有池参数都有默认值):
    初始大小:10个
    最小空闲连接数:3个
    增量:一次创建的最小单位(5个)
    最大空闲连接数:12个
    最大连接数:20个
    最大的等待时间:1000毫秒  超时间将异常。

四大连接参数
连接池也是使用四大连接参数来完成创建连接对象!

连接池返回的Connection对象。
调用它的close()不是关闭,而是把连接归还给池!

DBCP连接池:

/*
 * DBCP连接池
 */
public class Demo1 {
    @Test
    public void fun1() throws SQLException {
        /*
         * 1. 创建连接池对象
         * 2. 配置四大参数
         * 3. 配置池参数
         * 4. 得到连接对象
         */
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydb3");
        dataSource.setUsername("root");
        dataSource.setPassword("123");

        //设置连接池初始化参数
        dataSource.setMaxActive(20);
        dataSource.setMinIdle(3);
        dataSource.setMaxWait(1000);

        //得到连接
        Connection con = dataSource.getConnection();
        Connection con1 = new MyConnection(con);
        System.out.println(con1.getClass().getName());

        /**
         * 连接池内部使用四大参数创建了连接对象!即mysql驱动提供的Connection
         * 连接池使用mysql的连接对象进行了装饰,只对close()方法进行了增强!
         * 装饰之后的Connection的close()方法,用来把当前连接归还给池!
         */
        con1.close();//把连接归还给池!
    }
}

C3P0连接池:

开源免费。

使用连接池:
    先导包。
        c3p0-0.9.2-pre1.jar
        mchange-commons-0.2.jar
        mysql-connector-java-5.1.28-bin.jar

配置方法一:手动配置


        //  1. 创建连接池对象
            //    ComboPooledDataSource ds = new ComboPooledDataSource();
        //  2. 配置四大参数
        //  3. 配置池参数
        //  4. 得到连接对象

配置方法二:配置文件配置

    配置文件要求:
    文件名称:必须叫c3p0-config.xml
    文件位置:必须在src下

    使用时直接连接即可
    eg:
    <?xml version="1.0" encoding="UTF-8" ?>
    <c3p0-config>
        <default-config> 
            //连接四大参数配置
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="user">root</property>
            <property name="password">123456</property>

            //池参数配置
            <property name="acquireIncrement">3</property>
            <property name="initialPoolSize">10</property>
            <property name="minPoolSize">2</property>
            <property name="maxPoolSize">10</property>
        </default-config>
    </c3p0-config>


    一个配置文件中可以存在提供多种配置
        使用其他配置时需传参 配置名
    ComboPooledDataSource ds = new ComboPooledDataSource("orcale-config");

5、Tomcat配置JNDI资源JNDI


JNDI(Java Naming and Directory Interface),Java命名和目录接口。

    目的:通过统一方式来获取配置的资源。

    做法:在Tomcat服务器上配置连接池

1)在localhost下新建   项目名.xml
    E:\apache-tomcat-7.0.88\conf\Catalina\localhost\day18.xml

    注:此文件用完即删。 否则在项目关闭后,tomcat服务器将会抛出异常,不能正常使用
2)获取资源: 在Servlet下获取

1)在localhost下新建 项目名.xml

<?xml version="1.0" encoding="UTF-8" ?>
    <Context>
        <!--
        name:指定资源的名称
        factory:资源由谁来负责创建
        type:资源的类型
        其他的东西都是资源的参数
        -->
        <Resource name="jdbc/dataSource"
                factory="org.apache.naming.factory.BeanFactory"
                type="com.mchange.v2.c3p0.ComboPooledDataSource"
                jdbcUrl="jdbc:mysql://localhost:3306/mydb1"
                driverClass="com.mysql.jdbc.Driver"
                user="root"
                password="123456"
                acquireIncrement="5"
                initialPoolSize="10"
                />
    </Context>

2)获取资源 –> 在Servlet下获取:

public class AServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * 1. 创建JNDI的上下文对象
         */
        try {

            Context cxt = new InitialContext();
            // 2查询出入口
//          Context envContext = (Context)cxt.lookup("java:comp/env");
            // 3. 再进行二次查询,找到我们的资源
            // 使用的是名称与<Resource>元素的name对应
//          DataSource dataSource = (DataSource)envContext.lookup("jdbc/dataSource");

            DataSource dataSource = (DataSource)cxt.lookup("java:comp/env/jdbc/dataSource");

            //得到连接
            Connection con = dataSource.getConnection();
            System.out.println(con);
            con.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41307491/article/details/81475704