一.JDBC基础
1.1数据库驱动
我们安装好数据库后,我们的应用程序是不能直接使用数据库的,需要通过相应的数据库驱动程序,然后通过驱动程序才可以和数据库沟通,即JAVA应用程序--ORACLE/MYSQL/SQL SERVER驱动--ORACLE/MYSQL/SQL SERVER数据库。
1.2JDBC介绍
Oracle-Sun公司为了简化和统一对数据库的操作,定义了一套java操作数据库的规范(接口),称为JDBC,然后各个数据库厂商按照这个规范(接口)去实现,然后,广大的开发人员只需要学习JDBC规范(接口),然后通过JDBC加载相应的驱动程序,就可以完成操作数据库的工作,即:JAVA应用程序--JDBC--ORACLE/MYSQL/SQL SERVER驱动--ORACLE/MYSQL/SQL SERVER数据库。
在开发JDBC应用程序时需要用到两个包:java.sql和javax.sql,同时还需要导入相应的JDBC数据库驱动。
1.3编写JDBC程序
package com.boxiaoyuan.test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JdbcFirstDemo { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/jdbcStudy"; String username = "root"; String password = "aaaaaa"; Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //1.加载驱动 Class.forName("com.mysql.jdbc.Driver");//推荐使用这种方式来加载驱动 //2.获取与数据库的连接 conn = DriverManager.getConnection(url, username, password); //3.获取用于向数据库发送sql语句的statement stmt = conn.createStatement(); String sql = "select * from users"; //4.向数据库发送sql,并获取结果集resultSet rs = stmt.executeQuery(sql); //5.获取结果集中的数据 while (rs.next()) { System.out.println("name:" + rs.getObject("name")); } } catch (ClassNotFoundException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); }finally { if(rs != null) { try { //6.关闭连接,释放资源 rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt != null) { try { //6.关闭连接,释放资源 stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null) { try { //6.关闭连接,释放资源 conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
1.3.1DriverManager类
JDBC程序中的DriverManager类用于加载驱动,并且创建与数据库的连接,这个API的常用方法为:DriverManager.getConnection(url, user, password)。
在实际的开发过程中,加载驱动推荐的使用方式是Class.forName("com.mysql.jdbc.Driver");因为此方法不会导致驱动在内存中重复出现,灵活性很高。
1.3.2数据库URL
URL用于标识数据库的位置,通过URL可以让JDBC知道需要连接哪个数据库。
常用的数据库URL地址写法:
# sql server:jdbc:sqlserver://10.21.191.201:1433;DatabaseName=g1 # postgresql jdbc:postgresql://10.21.191.201:5432/g1 # oracle jdbc:oracle:thin:@//10.21.191.201:1521/g1 # mysql jdbc:mysql://localhost:3306/jdbcStudy
1.3.3Connection类
JDBC程序中的Connection标识数据库的连接,Connection是数据库编程中最重要的一个对象,客户端与数据库服务器的交互都是通过Connection对象完成的,这个对象的常用方法有:
1 createStatement() 创建一个静态sql语句对象 2 prepareStatement(String sql) 创建预编译的sql语句对象 3 prepareCall(String sql) 创建存储过程的sql语句对象
1.3.4Statement类
JDBC程序中的Statement对象用于向数据库发送SQL语句,这个对象的常用方法有:
1 executeUpdate(String sql) 执行更新操作的sql语句,create/alter/drop/insert/update/delete) 2 executeQuery(String sql) 执行查询操作的sql语句(select)
1.3.5ResultSet类
JDBC程序中的ResultSet用于标识SQL语句的执行结果,ResultSet对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用.next()方法后,可以使游标指向具体的数据行,然后再调用方法获取改行的数据。
获取任意类型的数据:
1 getObject(int index) 2 getObject(String columnName)
获取指定类型的数据:
1 getString(int index) 2 getString(String columnName)
另外,ResultSet还提供了对结果集进行滚动的方法:
1 next():移动到下一行 2 Previous():移动到前一行 3 absolute(int row):移动到指定行 4 beforeFirst():移动到ResultSet的最前面 5 afterLast():移动到Result的最后面
1.3.6释放资源
JDBC程序运行后,一定要释放程序运行中创建的与数据库进行交互的对象,这些对象通常为ResultSet,Statement,Connection,特别是Connection,如果该对象用完之后不能及时释放,很容易导致宕机的发生。为了确保资源释放代码能够运行,资源释放代码一定要放在finally语句中。
二.使用JDBC对数据库进行增删改查
JDBC中的Statement对象用于向数据库发送SQL语句,如果想要完成对数据库的增删改查,只需要通过这个对象发送增删改查即可。其中该对象的executeUpdate方法,用于向数据库发送增,删,改语句,该方法执行完之后,会返回一个整数表示数据库中多少行数据发生了变化;该对象的executeQuery方法,用于向数据库中发送查询语句,该方法返回ResultSet对象,表示查询结果。
2.1准备
首先在src目录下新增加一个配置文件,db.properties,然后在里面维护Mysql数据库的连接信息:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcStudy username=root password=aaaaaa
2.2编写JdbcUtils工具类
编写JdbcUtils工具类,用来连接数据库,获取数据库连接释放数据库连接:
package com.boxiaoyuan.www; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class JdbcUtils { private static String driver = null; private static String url = null; private static String username = null; private static String password = null; static { try { InputStream inStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); Properties prop = new Properties(); prop.load(inStream); //获取连接数据库的url地址 url = prop.getProperty("url"); //获取数据库连接驱动 driver = prop.getProperty("driver"); //获取数据库连接用户名 username = prop.getProperty("username"); //获取数据库连接密码 password = prop.getProperty("password"); //加载数据库驱动 Class.forName(driver); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } public static void release(Connection conn, Statement stmt, ResultSet rs) { if(rs != null) { try { //关闭结果集对象ResultSet rs.close(); } catch (SQLException e) { e.printStackTrace(); }finally { rs = null; } } if(stmt != null) { try { //关闭执行SQL的对象Statement stmt.close(); } catch (SQLException e) { e.printStackTrace(); }finally { stmt = null; } } if(conn != null) { try { //关闭数据库连接对象Connection conn.close(); } catch (SQLException e) { e.printStackTrace(); }finally { conn = null; } } } }
2.3使用Statement对象增删改查
package com.boxiaoyuan.www; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; public class Demo01 { @Test public void insert() { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); stmt = conn.createStatement(); String sql = "insert into users(id,name,password,email,birthday) values(12,'boxiaoyuan', '111111', 'test@qq.com', '1990-01-01')"; int num = stmt.executeUpdate(sql); if(num>0) { System.out.println("插入成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void delete() { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); stmt = conn.createStatement(); String sql = "delete from users where id='12'"; int num = stmt.executeUpdate(sql); if(num>0) { System.out.println("删除成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void update() { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); stmt = conn.createStatement(); String sql = "update users set password='222222' where id='12'"; int num = stmt.executeUpdate(sql); if(num>0) { System.out.println("修改成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void query() { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); stmt = conn.createStatement(); String sql = "select * from users"; rs = stmt.executeQuery(sql); while(rs.next()) { System.out.println(rs.getObject("name")+"----"+rs.getObject("password")); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } }
3.PreparedStatement对象介绍
PreparedStatement是Statement的子类,它的实例可以通过Connection.preparedStatement方法获得,与Statement对象比较,PreparedStatement可以避免SQL注入。
Statement会使数据库频繁的编译SQL,可能会造成数据库缓冲器溢出,但是PreparedStatement可以对SQL进行预编译,从而提高了数据库的执行效率。
3.1使用PreparedStatement对象增删改查
package com.boxiaoyuan.www; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.Test; public class Demo01 { @Test public void insert() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)"; stmt = conn.prepareStatement(sql); stmt.setInt(1, 13); stmt.setString(2, "bodayuan"); stmt.setString(3, "aaaaaa"); stmt.setString(4, "aa@sina.com"); stmt.setDate(5, new Date(new java.util.Date().getTime())); int num = stmt.executeUpdate(); if(num>0) { System.out.println("插入成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void delete() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "delete from users where id=?"; stmt = conn.prepareStatement(sql); stmt.setInt(1, 13); int num = stmt.executeUpdate(); if(num>0) { System.out.println("删除成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void update() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "update users set password=? where id=?"; stmt = conn.prepareStatement(sql); stmt.setString(1, "bbbbbb"); stmt.setInt(2, 13); int num = stmt.executeUpdate(); if(num>0) { System.out.println("修改成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } @Test public void query() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "select * from users where id=?"; stmt = conn.prepareStatement(sql); stmt.setInt(1, 13); rs = stmt.executeQuery(); while(rs.next()) { System.out.println(rs.getObject("name")+"----"+rs.getObject("password")); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } }
4.事务
4.1事务的概念
事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
4.2JDBC中使用事务
当JDBC程序向数据库获得一个Connection对象时,默认这个Connection对象会自动向数据库提交发送的SQL语句,如果想要关闭这种默认的提交方式,让多条SQL在一个事务中执行,可以使用如下的语句控制:
Connection.setAutoCommit(false);//开启事务 Connection.rollback();//回滚事务 Connection.commit();//提交事务
4.3示例
下面模拟银行转账的业务,用户A转账给用户B,用户B接收用户A的转账。
update account set money=money-10000 where name='A'; update account set money=money+10000 where name='B';
package com.boxiaoyuan.www; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.Test; public class Demo02 { /** * 模拟转账成功的场景 */ @Test public void transantion1() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); conn.setAutoCommit(false);//通知数据库开启事务 String sql = "update account set money=money-10000 where name='A'"; stmt = conn.prepareStatement(sql); stmt.executeUpdate(); String sql2 = "update account set money=money+10000 where name='B'"; stmt = conn.prepareStatement(sql2); stmt.executeUpdate(); conn.commit();//执行完上面两条语句后,提交事务 System.out.println("执行成功"); } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } /** * 模拟转账过程中出现异常,程序自动回滚 */ @Test public void testTransaction2() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); conn.setAutoCommit(false);//告诉数据库开始事务 String sql = "update account set money=money-10000 where name='A'"; stmt = conn.prepareStatement(sql); stmt.executeUpdate(); int m = 2/0;//程序出错,导致后续的程序无法进行,事务无法正常提交,数据库自动回滚 String sql2 = "update account set money=money+10000 where name='B'"; stmt = conn.prepareStatement(sql2); stmt.executeUpdate(); conn.commit();//提交事务 System.out.println("执行成功"); } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } /** * 模拟转账过程中出现异常,手动回滚事务 */ @Test public void testTransaction3() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); conn.setAutoCommit(false);//告诉数据库开始事务 String sql = "update account set money=money-10000 where name='A'"; stmt = conn.prepareStatement(sql); stmt.executeUpdate(); int m = 2/0;//程序出错 String sql2 = "update account set money=money+10000 where name='B'"; stmt = conn.prepareStatement(sql2); stmt.executeUpdate(); conn.commit();//提交事务 System.out.println("执行成功"); } catch (SQLException e) { try { conn.rollback();//捕获异常后手动执行数据库回滚操作 } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { JdbcUtils.release(conn, stmt, rs); } } }