使用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) {} } } |
在JDBC中常用的类有:
l DriverManager;
l Connection;
l Statement;
l ResultSet。
用于获取与数据库的连接:
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是否打错。
Connection最为重要的方法就是获取Statement,即获取一个SQL语句的执行器:
l Statementstmt = con.createStatement();
l Statementstmt = con.createStatement(int,int[c3] );
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类型的数据。
l 它是Statement接口的子接口;
l 优点:
Ø 防SQL攻击;
Ø 提高代码的可读性、可维护性;
Ø 提高效率!
l 使用:
Ø 获取PreparedStatement对象:
¨ 给出SQL模板!
¨ 调用Connection的PreparedStatement prepareStatement(Stringsql模板);
¨ 调用pstmt的setXxx()系列方法sql模板中的?赋值!
¨ 调用pstmt的executeUpdate()或executeQuery(),但它的方法都没有参数。
l PreparedStatement使用预处理:
Ø 每个PreparedStatement都与一个SQL模板绑定在一起。
Ø 数据库对SQL语句进行
¨ 校验SQL语句的语法
¨ 编译:生成一个与函数相似的东西
¨ 执行:执行时只是把参数传递过去而已,类似函数调用。
Ø 若第二次执行时,不用再次校验语法,不用再次校验和编译,而是直接执行。
批处理
每个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中配置的数据库的名字。
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
Student stu = qr.query(sql, newBeanHandler
Ø 多行结果:使用BeanHandlerList
List
2) 多表查询:多个表联合的查询结果集中一行数据对应一个Map
Ø 单行结果:使用MapHandler()
Map
Ø 多行结果:使用MapListHandler()
List
3) 结果集为单列
Ø 单列多行:使用ColumnListHandler(“列名称”)
List
Ø 单列单行:使用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模板和参数数组