第十三章.MySQL数据库与JDBC编程(下)
Posted lanshanxiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十三章.MySQL数据库与JDBC编程(下)相关的知识,希望对你有一定的参考价值。
JDBC的典型用法:
JDBC4.2常用接口和类简介:
DriverManager:用于管理JDBC驱动的服务类,程序中使用该类的主要功能是获取Connection对象,该类包含如下方法:
public static synchronized Connection getConnection(String url, String user, String pass) throws SQLException:该方法获得url对应数据库的连接
Connection:代表数据库连接对象,每个Connection代表一个物理连接会话。想要访问数据库,必须先获得数据库连接,该接口的常用方法如下:
1.Statement createStatement() throws SQLException:该方法返回一个Statement对象。
2.PreparedStatement prepareStatement(String sql) throws SQLException:该方法返回预编译的Statement对象,即将SQL语句提交到数据库进行预编译。
3.CallableStatement prepareCall(String sql) throws SQLException:该方法返回CallableStatement对象,该对象用于调用存储过程
上面三个方法都返回用于执行SQL语句的Statement对象,PreparedStatement、CallableStatement是Statement的子类,只有获得了Statement之后才可执行SQL语句。
除此之外,Connection还有如下几个用于控制事务的方法:
1.Savepoint setSavepoint():创建一个保存点
2.Savepoint setSavepoint(String name):以指定名字创建一个保存点
3.void setTransactionIsolation(int level):设置事务的隔离级别
4.void rollback():回滚事务
5.void rollback(Savepoint savepoint):将事务回滚到指定的保存点
6.void setAutoCommit(boolean autoCommit):关闭自动提交、打开事务
7.void commit():提交事务
Java7 为Connection新增了
setSchema(String schema)、getSchema()两个方法:用于控制该Connection访问的数据库Schema
setNetworkTimeout(Executor executor, int milliseconds)、getNetworkTimeout()两个方法:用于控制数据库连接超时行为。
Statement:用于执行SQL语句的工具接口,常用方法如下:
1.ResultSet executeQuery(String sql) throws SQLException:该方法用于执行查询语句,并返回查询结果对应的ResultSet对象。该方法只能用于执行查询语句
2.int executeUpdate(String sql) throws SQLException:该方法用于执行DML(数据操作语言)语句,并返回受影响的行数;该方法也可用于执行DDL(数据定义
语言)语句执行DDL语句将返回0
3.boolean execute(String sql) throws SQLException:该方法可执行任何SQL语句。若执行后第一个结果为ResultSet对象,则返回true;若执行后第一个结果为受影
响的行数或没有任何结果,则返回false。
Java7为Statement新增了closeOnCompletion()方法:若Statement执行了该方法,则当所有依赖于该Statement的ResultSet关闭时,该Statement会自动关闭。
Java7还为Statement提供了isCloseOnCompletion()方法:用于判断该Statement是否打开了“closeOnCompletion”.
Java8为Statement新增了多个重载的executeLargeUpdate()方法:这些方法相当于增强版的executeUpdate()方法,返回值类型为long,即当DML语句影响的记录条数超过
Integer.MAX_VALUE时,就应该使用executeLargeUpdate()方法。
PreparedStatement:预编译的Statement对象。PreparedStatement是Statement的子接口,它允许数据库预编译SQL语句(这些SQL语句通常带有参数),以后每次只
改变SQL命令的参数,避免数据库每次都需要编译SQL语句,因此性能更好。相对于Statement而言,使用PreparedStatement执行SQL语句时,无需再传入SQL语句,只
要为预编译的SQL语句传入参数数值即可。所以它比Statement多了如下方法:
1.void setXxx(int parameterIndex, Xxx value):该方法根据传入参数值的类型不同,需要使用不同的方法。传入的值根据索引传给SQL语句中指定位置的参数。
ResultSet:结果集对象。该对象包含访问查询结果的方法,ResultSet可以通过列索引或列名获得列数据。它包含了如下常用方法来移动记录指针:
1.void close():释放ResultSet对象。
2.boolean absolute(int row):将结果集的记录指针移动到第row行,若row是负数,则移动到倒数第row行。若移动后的记录指针指向一条有效记录,则该方法返回true
3.void beforeFirst():将ResultSet的记录指针定位到首行之前,这是ResultSet结果集记录指针的初始状态——记录指针的起始位置位于第一行之前
4.boolean first():将ResultSet的记录指针定位到首行。若移动后的记录指针指向一条有效记录,则该方法返回true。
5.boolean previous():将ResultSet的记录指针定位到上一行。若移动后的记录指针指向一条有效记录,则该方法返回true。
6.boolean next():将ResultSet的记录指针定位到下一行,若移动后的记录指针指向一条有效记录,则该方法返回true。
7.boolean last():将ResultSet的记录指针定位到最后一行,若移动后的记录指针指向一条有效记录,则该方法返回true。
8.void afterLast():将ResultSet的记录指针定位到最后一行之后。
JDBC编程步骤:
1.加载数据库驱动:
通常使用Class类的forName()静态方法来加载驱动:
Class.forName(driverClass);//driverClass就是数据库驱动类所对应的字符串。如:加载mysql的驱动代码
Class.forName("com.mysql.jdbc.Driver");
2.通过DriverManager获取数据库连接:
//获取数据库连接
DriverManager.getConnection(String url, String user, String pass);//数据库URL、登录数据库的用户名和密码。
数据库URL通常遵循如下写法:
jdbc:subprotocol:other stuff
jdbc是固定的写法,subprotocol指定连接到特定数据库的驱动,other stuff也不是固定的(由数据库定)
MySQL数据库的URL写法如下:
jdbc:mysql://hostname:port/databasename
3.通过Connection对象创建Statement对象。有如下三个方法:
1.createStatement():创建基本的Statement对象
2.prepareStatement(String sql):根据传入的SQL语句创建预编译的Statement对象
3.prepateCall(String sql):根据传入的SQL语句创建CllableStatement对象
4.使用Statement执行SQL语句。有如下三个方法:
1.execute():可执行任何SQL语句,但比较麻烦
2.executeUpdate():主要用于执行DML和DDL语句。执行DML语句返回受SQL语句影响的行数,执行DDL语句返回0
3.executeQuery():只能执行查询语句,执行后返回代表查询结果的ResultSet对象
5.操作结果集:
若执行SQL语句是查询语句,则执行结果将返回一个ResultSet对象,该对象里保存了SQL语句查询的结果。程序可通过操作该ResultSet对象来取出查询结果:
1.next()、previous()、first()、last()、beforeFirst()、afterLast()、absolute()等移动记录指针的方法
2.getXxx()方法获取记录指针指向行、特定列的值。该方法既可使用列索引作为参数,也可使用列名作为参数。使用列索引作为参数性能更好,使用列名作为参数可
读性更好
6.回收数据库资源:
包括关闭ResultSet、Statement和Connection等资源。
下面程序简单示范了JDBC编程,并通过ResultSet获得结果集的过程:
1 drop database if exists select_test; 2 create database select_test; 3 use select_test; 4 # 为了保证从表参照的主表存在,通常应该先建主表。 5 create table teacher_table 6 ( 7 # auto_increment:实际上代表所有数据库的自动编号策略,通常用作数据表的逻辑主键。 8 teacher_id int auto_increment, 9 teacher_name varchar(255), 10 primary key(teacher_id) 11 ); 12 create table student_table 13 ( 14 # 为本表建立主键约束 15 student_id int auto_increment primary key, 16 student_name varchar(255), 17 # 指定java_teacher参照到teacher_table的teacher_id列 18 java_teacher int, 19 foreign key(java_teacher) references teacher_table(teacher_id) 20 ); 21 insert into teacher_table 22 values 23 (null , \'Yeeku\'); 24 insert into teacher_table 25 values 26 (null , \'Leegang\'); 27 insert into teacher_table 28 values 29 (null , \'Martine\'); 30 insert into student_table 31 values 32 (null , \'张三\' , 1); 33 insert into student_table 34 values 35 (null , \'张三\' , 1); 36 insert into student_table 37 values 38 (null , \'李四\' , 1); 39 insert into student_table 40 values 41 (null , \'王五\' , 2); 42 insert into student_table 43 values 44 (null , \'_王五\' , 2); 45 46 insert into student_table 47 values 48 (null , null , 2); 49 insert into student_table 50 values 51 (null , \'赵六\' , null);
将驱动(mysql-connector-java-5.1.30-bin.jar)放到java目录的下的jre/lib/ext/目录下面。或者将驱动的路径添加到classpath环境变量后面。
1 import java.sql.Connection; 2 import java.sql.DriverManager; 3 import java.sql.Statement; 4 import java.sql.ResultSet; 5 6 public class ConnMySql{ 7 public static void main(String[] args) throws Exception{ 8 //1.加载驱动,使用反射知识,现在记住这么写 9 Class.forName("com.mysql.jdbc.Driver"); 10 try( 11 //2.使用DriverManager获取数据库连接 12 //其中返回的Connection就代表了Java程序和数据库的连接 13 //不同数据库的URL写法需要查询驱动文档,用户名、密码由DBA分配 14 Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456"); 15 //3.使用Connection来创建一个Statement对象 16 Statement stmt = conn.createStatement(); 17 //4.执行SQL语句 18 /* 19 Statement有三种执行SQL语句的方法: 20 1.execute()可执行任何SQL语句-返回一个boolean值,若执行后第一个结果是ResultSet,则返回true,否则返回false 21 2.executeQuery()执行select语句-返回查询到的结果集 22 3.executeUpdate()用于执行DML语句-返回一个整数,代表被SQL语句影响的记录条数 23 */ 24 ResultSet rs = stmt.executeQuery("select s.*, teacher_name" 25 + " from student_table s , teacher_table t" 26 + " where t.teacher_id = s.java_teacher")){ 27 //ResultSet有一系列的getXxx(列索引 | 列名)方法,用于获取记录指针 28 //指向行、特定列的值,不断地使用next()将记录指针下移一行 29 //若移动之后记录指针依然指向有效行,则next()方法返回true 30 while(rs.next()){ 31 System.out.println(rs.getInt(1) + "\\t" 32 + rs.getString(2) + "\\t" 33 + rs.getString(3) + "\\t" 34 + rs.getString(4)); 35 } 36 } 37 } 38 }
执行SQL语句的方式:
使用Java8新增的executeLargeUpdate()方法执行DDL和DML语句:
使用statement执行DDL和DML语句的步骤与执行普通查询语句的步骤基本相似,区别在于执行了DDL语句后返回值为0,执行了DML语句后返回值为受到影响的记录条数。
MySQL暂不支持executeLargeUpdate()方法。所以我们使用executeUpdate()方法。
下面的程序并没有直接把数据库连接信息写在代码中,而是使用一个mysql.ini文件(就是properties文件)来保存数据库连接信息,这是比较成熟的做法——当需要把应用程
序从开发环境移植到生产环境时,无需修改源代码,只需要修改mysql.ini配置文件即可:
mysql.ini文件内容:
mysql.ini和ExecuteDDL.java文件所放位置:
1 import java.io.FileInputStream; 2 import java.util.Properties; 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.Statement; 6 7 8 public class ExecuteDDL{ 9 private String driver; 10 private String url; 11 private String user; 12 private String pass; 13 public void initParam(String paramFile) throws Exception{ 14 //使用Properties类来加载属性文件 15 Properties props = new Properties(); 16 props.load(new FileInputStream(paramFile)); 17 driver = props.getProperty("driver"); 18 url = props.getProperty("url"); 19 user = props.getProperty("user"); 20 pass = props.getProperty("pass"); 21 } 22 23 public void createTable(String sql) throws Exception{ 24 //加载驱动 25 Class.forName(driver); 26 try( 27 //获取数据库连接 28 Connection conn = DriverManager.getConnection(url, user, pass); 29 //使用Connection来创建一个Statement对象 30 Statement stmt = conn.createStatement()){ 31 //执行DDL语句,创建数据表 32 stmt.executeUpdate(sql); 33 } 34 } 35 36 public static void main(String[] args) throws Exception{ 37 ExecuteDDL ed = new ExecuteDDL(); 38 ed.initParam("mysql.ini"); 39 ed.createTable("create table jdbc_test " 40 + "( jdbc_id int auto_increment primary key, " 41 + "jdbc_name varchar(255), " 42 + "jdbc_desc text);"); 43 System.out.println("------建表成功------"); 44 } 45 }
使用executeUpdate()方法执行DML语句:
和上面程序的步骤是一样的,只不过程序代码需要修改:
1 import java.io.FileInputStream; 2 import java.util.Properties; 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.Statement; 6 7 public class ExecuteDML{ 8 private String driver; 9 private String url; 10 private String user; 11 private String pass; 12 13 public void initParam(String paramFile) throws Exception{ 14 Properties props = new Properties(); 15 props.load(new FileInputStream(paramFile)); 16 driver = props.getProperty("driver"); 17 url = props.getProperty("url"); 18 user = props.getProperty("user"); 19 pass = props.getProperty("pass"); 20 } 21 22 public int insertData(String sql) throws Exception{ 23 //加载驱动 24 Class.forName(driver); 25 try( 26 //获取数据库连接 27 Connection conn = DriverManager.getConnection(url, user, pass); 28 //使用Connection来创建一个Statement对象 29 Statement stmt = conn.createStatement()){ 30 //执行SQL语句,返回受影响的记录条数 31 return stmt.executeUpdate(sql); 32 } 33 } 34 35 public static void main(String[] args) throws Exception{ 36 ExecuteDML ed = new ExecuteDML(); 37 ed.initParam("mysql.ini"); 38 int result = ed.insertData("insert into jdbc_test(jdbc_name,jdbc_desc)" 39 + "select s.student_name , t.teacher_name " 40 + "from student_table s , teacher_table t " 41 + "where s.java_teacher = t.teacher_id;"); 42 System.out.println("------系统中一共有" + result + "条记录受影响------"); 43 } 44 }
使用execute()方法执行SQL语句:
Statement的execute()方法几乎可以执行任何SQL语句,但它执行SQL语句比较麻烦,通常没有必要使用execute()方法来执行SQL语句。
使用execute()方法执行SQL语句的返回值只是boolean值,它表明执行该SQL语句是否返回了ResultSet对象,Statement提供了如下两个方法来获取执行结果:
1.getResultSet():获取该Statement执行查询语句所返回的ResultSet对象
2.getUpdateCount():获取该Statement执行DML语句所影响的记录行数。
下面程序示范了使用Statement的execute()方法来执行任意的SQL语句:
1 import java.util.Properties; 2 import java.io.FileInputStream; 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.Statement; 6 import java.sql.ResultSet; 7 import java.sql.ResultSetMetaData; 8 9 public class ExecuteSQL{ 10 private String driver; 11 private String url; 12 private String user; 13 private String pass; 14 15 public void initParam(String paramFile) throws Exception{ 16 //使用Properties类来加载属性文件 17 Properties props = new Properties(); 18 props.load(new FileInputStream(paramFile)); 19 driver = props.getProperty("driver"); 20 url = props.getProperty("url"); 21 user = props.getProperty("user"); 22 pass = props.getProperty("pass"); 23 } 24 25 public void executeSql(String sql) throws Exception{ 26 //加载数据库驱动 27 Class.forName(driver); 28 try( 29 //获取数据库连接 30 Connection conn = DriverManager.getConnection(url, user, pass); 31 //通过Connection创建一个Statement 32 Statement stmt = conn.createStatement()){ 33 //执行SQL语句,返回boolean值表示是否包含ResultSet 34 boolean hasResultSet = stmt.execute(sql); 35 //若执行后有ResultSet结果集 36 if(hasResultSet){ 37 try( 38 //获取结果集 39 ResultSet rs = stmt.getResultSet()){ 40 //ResultSetMetaData是用于分析结果集的元数据接口 41 ResultSetMetaData rsmd = rs.getMetaData(); 42 int columnCount = rsmd.getColumnCount(); 43 //迭代输出ResultSet对象 44 while(rs.next()){ 45 //依次输出每列的值 46 for(int i = 0; i < columnCount; i++){ 47 System.out.print(rs.getString(i + 1) + "\\t"); 48 } 49 System.out.print("\\n"); 50 } 51 } 52 }else{ 53 System.out.println("该SQL语句影响的记录有" + stmt.getUpdateCount() + "条"); 54 } 55 } 56 } 57 58 public static void main(String[] args) throws Exception{ 59 ExecuteSQL es = new ExecuteSQL(); 60 es.initParam("mysql.ini"); 61 System.out.println("------执行删除表的DDL语句------"); 62 es.executeSql("drop table if exists my_test"); 63 System.out.print("------执行建表的DDL语句------"); 64 es.executeSql("create table my_test" 65 + "(test_id int auto_increment primary key, " 66 + "test_name varchar(255))"); 67 System.out.println("------执行插入数据的DML语句------"); 68 es.executeSql("insert into my_test(test_name) " 69 + "select student_name from student_table"); 70 System.out.println("------执行查询数据的查询语句------"); 71 es.executeSql("select * from my_test"); 72 } 73 }
从结果看,执行DDL语句显示受影响记录条数;执行DML显示插入、修改、删除的记录条数;执行查询语句可以输出查询结果。
上面程序获得的SQL执行结果是没有根据各列的数据类型调用相应的getXxx()方法,而是直接使用getString()方法来取得值,这是可以的。
ResultSet的getString()方法几乎可以获取除了Blob之外的任意类型列的值,因为所有的数据类型都可以自动转换成字符串类型。
使用PreparedStatement执行SQL语句:
若经常要反复执行一条结构相似的SQL语句,如下两条:
insert into student_table values(null, \'张三\', 1);
insert into student_table values(null, \'李四\', 2);
对于这两条语句,它们结构相似,只是执行插入时插入的值不同而已。对于这种情况,可以使用占位符(?)参数的SQL语句来代替它:
insert into student_table values(null, ?, ?);
JDBC提供了PreparedStatement接口,它是Statement的子接口。它可以进行预编译SQL语句,预编译后的SQL语句被存储在PreparedStatement对象中,然后可以使用该
对象多次高效地执行该语句。使用PreparedStatement比使用Statement的效率要高。
创建PreparedStatement对象使用Connection的prepareStatement()方法,该方法需要传入一个SQL字符串,该SQL字符串可以包括占位符参数,如下:
//创建一个PreparedStatement对象
pstmt = conn.prepareStatement("insert into student_table values(null,?,1)");
PreparedStatement也提供了execute()、executeUpdate()、executeQuery()三个方法来执行SQL语句,不过这三个方法无需参数,因为PreparedStatement已经存储了预
编译的SQL语句。
使用PreparedStatement预编译SQL语句时,该SQL语句可以带占位符参数,因此在执行SQL语句之前必须为这些参数传入参数值,PreparedStatement提供了一系列
的setXxx(int index, Xxx value)方法来传入参数值。
下面程序示范了使用Statement和PreparedStatement分别插入100条记录的对比。:
1 import java.io.FileInputStream; 2 import java.util.Properties; 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.PreparedStatement; 6 import java.sql.Statement; 7 8 public class PreparedStatementTest{ 9 private String driver; 10 private String url; 11 private String user; 12 private String pass; 13 14 public void initParam(String paramFile) throws Exception{ 15 //使用Properties类加载属性文件 16 Properties props = new Properties(); 17 props.load(new FileInputStream(paramFile)); 18 driver = props.getProperty("driver"); 19 url = props.getProperty("url"); 20 user = props.getProperty("user"); 21 pass = props.getProperty("pass"); 22 //加载驱动 23 Class.forName(driver); 24 } 25 26 public void insertUseStatement() throws Exception{ 27 long start = System.currentTimeMillis(); 28 try( 29 //获取数据库连接 30 Connection conn = DriverManager.getConnection(url, user, pass); 31 //使用Connection来创建一个Statement对象 32 Statement stmt = conn.createStatement()) 33 { 34 //需要使用100条SQL语句来插入100条记录 35 for(int i = 0; i < 100; i++){ 36 stmt.executeUpdate("insert into student_table values(" 37 + "null,\'姓名" + i + "\', 1)"); 38 } 39 System.out.println("使用Statement费时:" 40 + (System.currentTimeMillis() - start)); 41 } 42 } 43 44 public void insertUsePrepare() throws Exception{ 45 long start = System.currentTimeMillis(); 46 try( 47 //获取数据库连接 48 Connection conn = DriverManager.getConnection(url, user, pass); 49 //使用Connection来创建一个PreparedStatement对象 50 PreparedStatement pstmt = conn.prepareStatement("insert into student_table values(null,?,1)")) 51 { 52 //100次为PreparedStatement的参数设值,就可以插入100条记录以上是关于第十三章.MySQL数据库与JDBC编程(下)的主要内容,如果未能解决你的问题,请参考以下文章