JDBC、事务、数据库连接池、DBUtils

JDBC

使用JDBC连接数据库的规范代码(要求能默写出)

    @Test

    public void query() {

       Connection con = null;

       Statement stmt = null;

       ResultSet rs = null;

     try {

Class.forName("com.mysql.jdbc.Driver");

            String url = "jdbc:mysql://localhost:3306/mydb1";

           

           con = DriverManager.getConnection(url, "root", "123");

           stmt = con.createStatement();

           String sql = "select * from user";

           rs = stmt.executeQuery(sql);

           while(rs.next()) {

              String username = rs.getString(1);

              String password = rs.getString(2);

              System.out.println(username + ", " + password);

           }

       } catch(Exception e) {

           throw new RuntimeException(e);

       } finally {

           try {

              if(rs != null) rs.close();

              if(stmt != null) stmt.close();

              if(con != null) con.close();

         } catch(SQLException e) {}

       }

    }

 

对象介绍:

1 JDBC中的主要类(接口)

在JDBC中常用的类有:

l  DriverManager;

l  Connection;

l  Statement;

l  ResultSet。

2 DriverManager

用于获取与数据库的连接:

1.       Class.forName(“com.mysql.jdbc.Driver”);//注册驱动

2.       Stringurl = “jdbc:mysql://localhost:3306/mydb1”;

3.       Stringusername = “root”;

4.       Stringpassword = “123”;

5.      Connectioncon = DriverManager.getConnection(url, username, password);

 

上面代码可能出现的两种异常:

1.       ClassNotFoundException:这个异常是在第1句上出现的,出现这个异常有两个可能:

l  你没有给出mysql的jar包;

l  你把类名称打错了,查看类名是不是com.mysql.jdbc.Driver。

 

2.      SQLException:这个异常出现在第5句,出现这个异常就是三个参数的问题,往往username和password一般不是出错,所以需要认真查看url是否打错。

3 Connection

Connection最为重要的方法就是获取Statement,即获取一个SQL语句的执行器:

l  Statementstmt = con.createStatement();

l  Statementstmt = con.createStatement(int,int[c3] );

4  Statement

StatementSQL语句执行器,用于向数据库发送SQL语句:

l  int executeUpdate[c4] (Stringsql):执行更新操作,即执行insert、update、delete语句;

l  ResultSetexecuteQuery[c5] (Stringsql):执行查询操作,执行查询操作会返回ResultSet,即结果集。

5 ResultSet

         两个重要的方法:next()和getXXX(“”)

可以通过next()方法使ResultSet的游标向下移动。

当游标移动到你需要的行时,就需要来获取该行的数据了,ResultSet提供了一系列的获取列数据的方法:

l  StringgetString(int columnIndex):获取指定列的String类型数据;

l  intgetInt(int columnIndex):获取指定列的int类型数据;

l  doublegetDouble(int columnIndex):获取指定列的double类型数据;

l  boolean getBoolean(intcolumnIndex):获取指定列的boolean类型数据;

l  ObjectgetObject(int columnIndex):获取指定列的Object类型的数据。

PreparedStatement

l  它是Statement接口的子接口;

l  优点:

Ø  防SQL攻击;

Ø  提高代码的可读性、可维护性;

Ø  提高效率!

l  使用:

Ø  获取PreparedStatement对象:

¨        给出SQL模板!

¨        调用Connection的PreparedStatement prepareStatement(Stringsql模板);

¨        调用pstmt的setXxx()系列方法sql模板中的?赋值!

¨        调用pstmt的executeUpdate()或executeQuery(),但它的方法都没有参数。

l  PreparedStatement使用预处理:

Ø  每个PreparedStatement都与一个SQL模板绑定在一起。

Ø  数据库对SQL语句进行

¨        校验SQL语句的语法

¨        编译:生成一个与函数相似的东西

¨        执行:执行时只是把参数传递过去而已,类似函数调用。

Ø  若第二次执行时,不用再次校验语法,不用再次校验和编译,而是直接执行。

批处理

PreparedStatement批处理

每个PreparedStatement对象都绑定一条SQL模板,所以向PreparedStatement中添加的不是SQL语句,而是给“?”赋值。

           con = JdbcUtils.getConnection();

           String sql = "insert into stu values(?,?,?,?)";

           pstmt = con.prepareStatement(sql);

           for(int i = 0; i < 10; i++) {

              pstmt.setString(1, "S_10" + i);

              pstmt.setString(2, "stu" + i);

              pstmt.setInt(3, 20 + i);

              pstmt.setString(4, i % 2 == 0 ? "male" : "female");

              pstmt.addBatch() ;

           }

           pstmt.executeBatch ();

 

事务

1.        事务的特性:ACID

1)        原子性:事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。

2)        一致性:事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。

3)        隔离性:在并发操作中,不同事务之间相互隔离,相互干扰。

4)        持久性:一旦事务提交成功,事务中所有的数据操作被持久化到数据库中。即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

2.        使用

1)        MySQL操作事务

Ø  开始事务:starttransaction

Ø  结束事务:commit或rollback

2)        JDBC事务

Ø  开始事务:con.setAutoCommit(false);

Ø  结束事务;con.commit()或con.rollback();

Ø  保存点:回滚到保存点。

设置保存点:Savepointsp = con.setSavepoint();

回滚到保存点:con.rollback(sp);

3.        事务的隔离级别:

1)        三种并发读问题

Ø  读:读到未提交

Ø  不可重复读:两次读取不一致,读取到另一事务修改的记录

Ø  读:两次读取不一致,读取到另一事务插入的记录

2)        四大隔离级别:

Ø  SERIALIZABLE(串行化):对同一数据串行访问的,即非并发。所以不会出现任何并发问题。缺点:易出现死锁,效率太低,不用。

Ø  REPEATABLE READ(可重复读):防止了脏读、不可重复读,但没有防止幻读

Ø  READ COMMITTED(读已提交):防止了脏读,但没有防止不可重复读,以及幻读

Ø  READ UNCOMMITTED(读未提交):可能出现所有并发问题,效率最高,但不可用!

MySQL默认事务隔离级别为:REPEATABLE READ

Oracle默认事务隔离级别为:READ COMMITTED

3)        MySQL设置事务隔离级别

Ø  查看:select@@tx_isolation

Ø  设置:settransaction isolation level 四选一

4)        JDBC设置事务隔离级别

Ø  con.setTransactionIsolation(四选一)

数据库连接池:

1.        作用:用来管理数据库连接的生命周期。

2.        优点:节省资源,提高性能。

3.        接口:java提供的连接池接口javax.sql.DataSource,连接池厂商的连接池类需要实现这一接口。

4.        常用的数据库连接池:

1)        DBCP:

实现类:BasicDataSource()

使用:

Ø  获得一个数据库连接池:BasicDataSourceds = new BasicDataSource()

Ø  设置四大参数:通过BasicDataSource提供的4个set方法实现

ds.setUsername("root");

ds.setPassword("123");

ds.setUrl("jdbc:mysql://localhost:3306/mydb1");

ds.setDriverClassName("com.mysql.jdbc.Driver")

Ø  设置连接池属性:包含连接池最大连接数、初始连接数、最大空闲数和最小空闲数等。

Ø  通过数据库连接池获得连接:Connectioncon = ds.getConnection();

2)        C3P0:

实现类:ComboPooledDataSource

使用:同DBCP

特点:

支持配置文件配置:

Ø  通过默认配置初始化连接池:c3p0-config.xml放到src目录下。

Ø  创建:ComboPooledDataSourceds = new ComboPooledDataSource(); 无参构造

通过命名配置初始化连接池

Ø  创建:

ComboPooledDataSource ds = newComboPooledDataSource("oracle-config");参数为在web.xml中配置的数据库的名字。

DBUtils:

1.        核心类:QueryRunner、ResultSetHandler

1)        QueryRunner:与数据库连接池相关的执行器。

2)        ResultSetHandler:用于查询语句,规定表中的表中一行数据转换为一个实例对象

2.        创建QueryRunner:需要为其传入一个数据库连接池或一个连接

DataSource ds = JdbcUtils.getDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

3.        更新:Update:qr.update(sql, "u1", "zhangSan","123");即传入SQL模板和参数

4.        查询:

1)        单表查询:查询结果中每一行对应一个Bean的实例

Ø  单行结果:使用BeanHandler(Class.class)

Student stu = qr.query(sql, newBeanHandler(Student.class));

Ø  多行结果:使用BeanHandlerList(Class.class)

List list = qr.query(sql, new BeanListHandler(Student.class));

2)        多表查询:多个表联合的查询结果集中一行数据对应一个Map对象

Ø  单行结果:使用MapHandler()

Map map = qr.query(sql, new MapHandler());

Ø  多行结果:使用MapListHandler()

List> list = qr.query(sql, newMapListHandler() );

3)        结果集为单列

Ø  单列多行:使用ColumnListHandler(“列名称”)

List list = qr.query(sql, newColumnListHandler("name")) ;

Ø  单列单行:使用ScalarHander()

Number number = (Number)qr.query(sql, new ScalarHandler());

5.        批处理:

DataSource ds =JdbcUtils.getDataSource();

         QueryRunnerqr = new QueryRunner(ds);

         Stringsql = "insert into tab_student values(?,?,?,?)";

         Object[][]params = new Object[10][]; //表示要插入10行记录

         for(inti = 0; i < params.length; i++) {

                   params[i]= new Object[]{"S_300" + i, "name" + i, 30 + i,i%2==0?"男":"女"};

         }

         qr.batch (sql, params);//参数为SQL模板和参数数组



你可能感兴趣的:(Java,Web)