这篇文章里,我们来讨论一些和JDBC相关的话题。

  概述

  尽管在实际开发过程中,我们一般使用ORM框架来代替传统的JDBC,例如Hibernate或者iBatis,但JDBC是Java用来实现数据访问的基础,掌握它对于我们理解Java的数据操作流程很有帮助。

  JDBC的全称是Java Database Connectivity。

  JDBC对数据库进行操作的流程:

  • 连接数据库
  • 发送数据请求,即传统的CRUD指令
  • 返回操作结果集

  JDBC中常用的对象包括:

  • ConnectionManager
  • Connection
  • Statement
  • CallableStatement
  • PreparedStatement
  • ResultSet
  • SavePoint

  一个简单示例

  我们来看下面一个简单的示例,它使用JDK自带的Derby数据库,创建一张表,插入一些记录,然后将记录返回:

1 private static void test1() throwsSQLException2 {3     String driver = "org.apache.derby.jdbc.EmbeddedDriver";4     String dbURL = "jdbc:derby:EmbeddedDB;create=true";5
6     Connection con = null;7     Statement st = null;8     try
9 {10 Class.forName(driver);11         con =DriverManager.getConnection(dbURL);12         st =con.createStatement();13         st.execute("create table foo(ID INT NOT NULL, NAME VARCHAR(30))");14         st.executeUpdate("insert into foo(ID,NAME) values(1, 'Zhang San')");15
16         ResultSet rs = st.executeQuery("select ID,NAME from foo");17
18         while(rs.next())19 {20             int id = rs.getInt("ID");21             String name = rs.getString("NAME");22             System.out.println("ID=" + id + "; NAME=" +name);23 }24 }25     catch(Exception ex)26 {27 ex.printStackTrace();28 }29     finally
30 {31         if (st != null) st.close();32         if (con != null) con.close();33 }34 }

  如何建立数据库连接

  上面的示例代码中,建立数据库连接的部分如下:

String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String dbURL= "jdbc:derby:EmbeddedDB;create=true";Class.forName(driver);
con = DriverManager.getConnection(dbURL);

  建立数据库连接的过程,可以分为两步:

  1)加载数据库驱动,即上文中的driver以及Class.forName(dirver)

  2)定位数据库连接字符串, 即dbURL以及DriverManager.getConnection(dbURL)

  不同的数据库,对应的dirver和dbURL不同,但加载驱动和建立连接的方式是相同的,即只需要修改上面driver和dbURL的值就可以了。

  自动加载数据库驱动

  如果我们每次建立连接时,都要使用Class.forName(...)来手动加载数据库驱动,这样会很麻烦,我们可以通过配置文件的方式,来保存数据库驱动的信息。

  我们可以在classpath中,即编译出来的.class的存放路径,添加如下文件:

META-INF\services\java.sql.Driver

  对应的内容就是JDBC驱动的全路径,也就是上面driver变量的值:

org.apache.derby.jdbc.EmbeddedDriver

  接下来,我们在程序中,就不需要再显示的用Class.forName(...)来加载驱动了,它会被自动加载进来,当我们的数据库发生变化时,只需要修改这个文件就可以了,例如当我们的数据库由Derby变为MySQL时,只需要将上述的配置修改为:

com.mysql.jdbc.Driver

  但是,需要注意一点,这里只是配置了JDBC驱动的全路径,并没有包含jar文件的信息,因此,我们还是需要将包含该驱动的jar文件手动的放置到程序的classpath中。

  JDBC中的基本操作

  对于数据库操作来说,CRUD操作应该是最常见的操作了, 即我们常说的增、删、查、改。

  JDBC是使用Statement和ResultSet来完成这些操作的。

  如何实现CRUD

  下面是一个实现CRUD的示例:

1 private static void insertTest() throwsSQLException2 {3     String dbURL = "jdbc:mysql://localhost/test";4     Connection con = DriverManager.getConnection(dbURL, "root", "123");5     Statement st =con.createStatement();6     st.execute("insert into user(ID,NAME) values(1, 'Zhang San')");7     st.execute("insert into user(ID,NAME) values(2, 'Li Si')");8     st.execute("insert into user(ID,NAME) values(3, 'Wang Wu')");9     System.out.println("=====insert test=====");10 showUser(st);11 st.close();12 con.close();13 }14
15 private static void deleteTest() throwsSQLException16 {17     String dbURL = "jdbc:mysql://localhost/test";18     Connection con = DriverManager.getConnection(dbURL, "root", "123");19     Statement st =con.createStatement();20     st.execute("delete from user where ID=3");21     System.out.println("=====delete test=====");22 showUser(st);23 st.close();24 con.close();25 }26
27 private static void updateTest() throwsSQLException28 {29     String dbURL = "jdbc:mysql://localhost/test";30     Connection con = DriverManager.getConnection(dbURL, "root", "123");31     Statement st =con.createStatement();32     st.executeUpdate("update user set NAME='TEST' where ID=2");33     System.out.println("=====update test=====");34 showUser(st);35 st.close();36 con.close();37 }38
39 private static void showUser(Statement st) throwsSQLException40 {41     ResultSet rs = st.executeQuery("select ID, NAME from user");42     while(rs.next())43 {44         int id = rs.getInt("ID");45         String name = rs.getString("NAME");46         System.out.println("ID:" + id + "; NAME=" +name);47 }48 rs.close();49 }

  我们顺序调用上面的测试方法:

1 insertTest();2 deleteTest();3 updateTest();

  执行结果如下:

=====insert test=====ID:1; NAME=Zhang San
ID:2; NAME=Li Si
ID:3; NAME=Wang Wu=====delete test=====ID:1; NAME=Zhang San
ID:2; NAME=Li Si=====update test=====ID:1; NAME=Zhang San
ID:2; NAME=TEST

  上面代码中的showUser方法会把user表中的所有记录打印出来。

  如何调用存储过程

  存储过程是做数据库开发时经常使用的技术,它可以通过节省编译时间的方式来提升系统性能,我们这里的示例使用MySQL数据库。

  如何调用不带参数的存储过程

  假设我们现在有一个简单的存储过程,它只是返回user表中的所有记录,存储过程如下:

1 CREATE DEFINER=`root`@`localhost` PROCEDURE`GetUser`()2 BEGIN
3 select ID,NAME from user;4 END

  我们可以使用CallableStatement来调用存储过程:

1 private static void execStoredProcedureTest() throws SQLException2 {3     String dbURL = "jdbc:mysql://localhost/test";4     Connection con = DriverManager.getConnection(dbURL, "root", "123");5     CallableStatement cst =con.prepareCall("call GetUser()");6     ResultSet rs =cst.executeQuery();7     while(rs.next())8 {9         int id =rs.getInt("ID");10         String name =rs.getString("NAME");11         System.out.println("ID:" + id + "; NAME=" +name);12 }13     rs.close();14     cst.close();15     con.close();16 }

  它的执行结果如下:

ID:1; NAME=Zhang San
ID:2; NAME=TEST

  如何调用带参数的存储过程

  MySQL的存储过程中的参数分为三种:in/out/inout,我们可以把in看做入力参数,out看做出力参数,JDBC对这两种类型的参数设置方式不同:

  1)in, JDBC使用类似于cst.set(1, 10)的方式来设置

  2)out,JDBC使用类似于cst.registerOutParameter(2, Types.VARCHAR);的方式来设置

  我们来看一个in参数的示例,假设我们希望返回ID为特定值的user信息,存储过程如下:

1 CREATE DEFINER=`root`@`localhost` PROCEDURE `GetUserByID`(in id int)2 BEGIN
3 set @sqlstr=concat('select * from user where ID=', id);4 prepare psmt from @sqlstr;5 executepsmt;6 END

  Java的调用代码如下:

1 private static void execStoredProcedureTest2(int id) throwsSQLException2 {3     String dbURL = "jdbc:mysql://localhost/test";4     Connection con = DriverManager.getConnection(dbURL, "root", "123");5     CallableStatement cst = con.prepareCall("call GetUserByID(?)");6     cst.setInt(1, id);7     ResultSet rs =cst.executeQuery();8     while(rs.next())9 {10         String name = rs.getString("NAME");11         System.out.println("ID:" + id + "; NAME=" +name);12 }13 rs.close();14 cst.close();15 con.close();16 }

  我们执行下面的语句:

execStoredProcedureTest2(1);

  结果如下:

ID:1; NAME=Zhang San

  对于out类型的参数,调用方式类似,不再赘述。

  获取数据库以及结果集的metadata信息

  在JDBC中,我们不仅能够对数据进行操作,我们还能获取数据库以及结果集的元数据信息,例如数据库的名称、驱动信息、表信息;结果集的列信息等。

  获取数据库的metadata信息

  我们可以通过connection.getMetaData方法来获取数据库的元数据信息,它的类型是DatabaseMetaData。

1 private static void test1() throwsSQLException2 {3     String dbURL = "jdbc:mysql://localhost/mysql";4     Connection con = DriverManager.getConnection(dbURL, "root", "123");5
6     DatabaseMetaData dbmd =con.getMetaData();7
8     System.out.println("数据库:" + dbmd.getDatabaseProductName() + " " +dbmd.getDatabaseProductVersion());9     System.out.println("驱动程序:" + dbmd.getDriverName() + " " +dbmd.getDriverVersion());10
11     ResultSet rs = dbmd.getTables(null, null, null, null);12     System.out.println(String.format("|%-26s|%-9s|%-9s|%-9s|", "表名称","表类别","表类型","表模式"));13     while(rs.next())14 {15         System.out.println(String.format("|%-25s|%-10s|%-10s|%-10s|",16                 rs.getString("TABLE_NAME"),rs.getString("TABLE_CAT"),17                 rs.getString("TABLE_TYPE"), rs.getString("TABLE_SCHEM")));18 }19 }

  这里我们使用的数据库是MySQL中自带的默认数据库:mysql,它会记录整个数据库服务器中的一些信息。上述代码执行结果如下:

数据库:MySQL 5.5.28驱动程序:MySQL-AB JDBC Driver mysql-connector-java-5.0.4 ( $Date: 2006-10-19 17:47:48 +0200 (Thu, 19 Oct 2006) $, $Revision: 5908$ )|表名称                       |表类别      |表类型      |表模式      |
|columns_priv             |mysql     |TABLE     |null      |
|db                       |mysql     |TABLE     |null      |
|event                    |mysql     |TABLE     |null      |
|func                     |mysql     |TABLE     |null      |。。。

  由于mysql中表比较多,上述结果只截取了一部分。

  获取结果集的元数据信息

  我们可以通过使用resultset.getMetaData方法来获取结果集的元数据信息,它的类型是ResultSetMetaData。

1 private static void test2() throwsSQLException2 {3     String dbURL = "jdbc:mysql://localhost/test";4     Connection con = DriverManager.getConnection(dbURL, "root", "123");5     Statement st =con.createStatement();6     ResultSet rs = st.executeQuery("select ID, NAME from user");7     ResultSetMetaData rsmd =rs.getMetaData();8     for (int i = 1; i <= rsmd.getColumnCount(); i++)9 {10         System.out.println("Column Name:" + rsmd.getColumnName(i) + "; Column Type:" +rsmd.getColumnTypeName(i));11 }12 }

  它的执行结果如下:

Column Name:ID; Column Type:INTEGER UNSIGNED
Column Name:NAME; Column Type:VARCHAR

  可以看到,它返回类结果集中每一列的名称和类型。

  基于ResultSet的操作

  当我们需要对数据库进行修改时,除了上述通过Statement完成操作外,我们也可以借助ResultSet来完成。

  需要注意的是,在这种情况下,我们定义Statement时,需要添加参数。

  Statement构造函数可以包含3个参数:

  • resultSetType,它的取值包括:ResultSet.TYPE_FORWARD_ONLYResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_SENSITIVE,默认情况下,该参数的值是ResultSet.TYPE_FORWARD_ONLY
  • resultSetConcurrency,它的取值包括:ResultSet.CONCUR_READ_ONLYResultSet.CONCUR_UPDATABLE,默认情况下,该参数的值是ResultSet.CONCUR_READ_ONLY
  • resultSetHoldability,它的取值包括:ResultSet.HOLD_CURSORS_OVER_COMMITResultSet.CLOSE_CURSORS_AT_COMMIT

  为了使得ResultSet能够对数据进行操作我们需要:

  • 将resultSetType设置为ResultSet.TYPE_SCROLL_SENSITIVE
  • 将resultSetConcurrency设置为ResultSet.CONCUR_UPDATABLE

  在通过ResultSet对数据进行调整的过程中,下面方法可能会被调用:

  • resultset.last()
  • resultset.first()
  • resultset.moveToInsertRow()
  • resultset.absolute()
  • resultset.setxxx()
  • resultset.updateRow()
  • resultset.insertRow()

  下面是一个通过ResultSet对数据进行增、删、改的示例:

1 private static void getResultCount() throwsSQLException2 {3     System.out.println("=====Result Count=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     Statement st =con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);7     ResultSet rs = st.executeQuery("select * from user");8 rs.last();9     System.out.println("返回结果的条数:"+rs.getRow());10 rs.first();11
12 rs.close();13 st.close();14 con.close();15 }16
17 private static void insertDataToResultSet() throwsSQLException18 {19     System.out.println("=====Insert=====");20     String dbURL = "jdbc:mysql://localhost/test";21     Connection con = DriverManager.getConnection(dbURL, "root", "123");22     Statement st =con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);23     ResultSet rs = st.executeQuery("select ID,NAME from user");24 rs.moveToInsertRow();25     rs.updateInt(1, 4);26     rs.updateString(2, "Xiao Ming");27 rs.insertRow();28 showUser(st);29
30 rs.close();31 st.close();32 con.close();33 }34
35 private static void updateDataToResultSet() throwsSQLException36 {37     System.out.println("=====Update=====");38     String dbURL = "jdbc:mysql://localhost/test";39     Connection con = DriverManager.getConnection(dbURL, "root", "123");40     Statement st =con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);41     ResultSet rs = st.executeQuery("select * from user");42 rs.last();43     int count =rs.getRow();44 rs.first();45 rs.absolute(count);46     rs.updateString(2, "Xiao Qiang");47 rs.updateRow();48 showUser(st);49
50 rs.close();51 st.close();52 con.close();53 }54
55 private static void delDataFromResultSet() throwsSQLException56 {57     System.out.println("=====Delete=====");58     String dbURL = "jdbc:mysql://localhost/test";59     Connection con = DriverManager.getConnection(dbURL, "root", "123");60     Statement st =con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);61     ResultSet rs = st.executeQuery("select * from user");62 rs.last();63     int count =rs.getRow();64 rs.first();65 rs.absolute(count);66 rs.deleteRow();67 showUser(st);68
69 rs.close();70 st.close();71 con.close();72 }

  分别调用上述方法:

1 getResultCount();2 insertDataToResultSet();3 updateDataToResultSet();4 delDataFromResultSet();

  执行结果如下:

=====Result Count=====返回结果的条数:2
=====Insert=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:4; NAME=Xiao Ming=====Update=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:4; NAME=Xiao Qiang=====Delete=====ID:1; NAME=Zhang San
ID:2; NAME=TEST

  可以看到我们对ID为4的记录进行了插入、更新和删除操作。

  预处理以及批处理

  预处理和批处理都是用来提升系统性能的方式,一种是利用数据库的缓存机制,一种是利用数据库一次执行多条语句的方式。

  预处理

  数据库服务器接收到Statement后,一般会解析Statement、分析是否有语法错误、定制最优的执行计划,这个过程可能会降低系统的 性能。一般的数据库服务器都这对这种情况,设计了缓存机制,当数据库接收到指令时,如果缓存中已经存在,那么就不再解析,而是直接运行。

  这里相同的指令是指sql语句完全一样,包括大小写。

  JDBC使用PreparedStatement来完成预处理:

1 private static void test1() throwsSQLException2 {3     System.out.println("=====Insert a single record by PreparedStatement=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");7     pst.setInt(1, 5);8     pst.setString(2, "Lei Feng");9 pst.executeUpdate();10 showUser(pst);11 pst.close();12 con.close();13 }

  执行结果如下:

=====Insert a single record by PreparedStatement=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng

  批处理

  批处理是利用数据库一次执行多条语句的机制来提升性能,这样可以避免多次建立连接带来的性能损失。

  批处理使用Statement的addBatch来添加指令,使用executeBatch方法来一次执行多条指令:

1 private static void test2() throwsSQLException2 {3     System.out.println("=====Insert multiple records by Statement & Batch=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     Statement st =con.createStatement();7     st.addBatch("insert into user(id,name) values(6,'Xiao Zhang')");8     st.addBatch("insert into user(id,name) values(7,'Xiao Liu')");9     st.addBatch("insert into user(id,name) values(8,'Xiao Zhao')");10 st.executeBatch();11 showUser(st);12 st.close();13 con.close();14 }

  执行结果如下:

=====Insert multiple records by Statement & Batch=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:6; NAME=Xiao Zhang
ID:7; NAME=Xiao Liu
ID:8; NAME=Xiao Zhao

  预处理和批处理相结合

  我们可以把预处理和批处理结合起来,利用数据库的缓存机制,一次执行多条语句:

1 private static void test3() throwsSQLException2 {3     System.out.println("=====Insert multiple records by PreparedStatement & Batch=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");7     pst.setInt(1, 9);8     pst.setString(2, "Xiao Zhang");9 pst.addBatch();10     pst.setInt(1, 10);11     pst.setString(2, "Xiao Liu");12 pst.addBatch();13     pst.setInt(1, 11);14     pst.setString(2, "Xiao Zhao");15 pst.addBatch();16 pst.executeBatch();17 showUser(pst);18 pst.close();19 con.close();20 }

  执行结果如下:

=====Insert multiple records by PreparedStatement & Batch=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei FengID:9; NAME=Xiao Zhang
ID:10; NAME=Xiao Liu
ID:11; NAME=Xiao Zhao

  数据库事务

  谈到数据库开发,事务是一个不可回避的话题,JDBC默认情况下,是每一步都自动提交的,我们可以通过设置 connection.setAutoCommit(false)的方式来强制关闭自动提交,然后通过connection.commit()和 connection.rollback()来实现事务提交和回滚。

  简单的数据库事务

  下面是一个简单的数据库事务的示例:

1 private static void transactionTest1() throwsSQLException2 {3     System.out.println("=====Simple Transaction test=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     Statement st =con.createStatement();7     try
8 {9         con.setAutoCommit(false);10         st.executeUpdate("insert into user(id,name) values(12, 'Xiao Li')");11 con.commit();12 }13     catch(Exception ex)14 {15 ex.printStackTrace();16 con.rollback();17 }18     finally
19 {20         con.setAutoCommit(true);21 showUser(st);22         if (st != null) st.close();23         if (con != null) con.close();24 }25 }

  连续执行上述方法两次,我们可以得出下面的结果:

=====Simple Transaction test=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:12; NAME=Xiao Li=====Simple Transaction test=====ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:12; NAME=Xiao Li
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry'12' for key 'PRIMARY'at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)at com.mysql.jdbc.Connection.execSQL(Connection.java:3170)at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1316)at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1235)at sample.jdbc.mysql.ResultSetSample.transactionTest1(ResultSetSample.java:154)at sample.jdbc.mysql.ResultSetSample.main(ResultSetSample.java:17)

  可以看到,第一次调用时,操作成功,事务提交,向user表中插入了一条记录;第二次调用时,发生主键冲突异常,事务回滚。

  带有SavePoint的事务

  当我们的事务操作中包含多个处理,但我们有时希望一些操作完成后可以先提交,这样可以避免整个事务的回滚。JDBC使用SavePoint来实现这一点。

1 private static void transactionTest2() throwsSQLException2 {3     System.out.println("=====Simple Transaction test=====");4     String dbURL = "jdbc:mysql://localhost/test";5     Connection con = DriverManager.getConnection(dbURL, "root", "123");6     Statement st =con.createStatement();7     Savepoint svpt = null;8     try
9 {10         con.setAutoCommit(false);11         st.executeUpdate("insert into user(id,name) values(13, 'Xiao Li')");12         st.executeUpdate("insert into user(id,name) values(14, 'Xiao Wang')");13         svpt = con.setSavepoint("roll back to here");14         st.executeUpdate("insert into user(id,name) values(15, 'Xiao Zhao')");15         st.executeUpdate("insert into user(id,name) values(13, 'Xiao Li')");16 con.commit();17 }18     catch(Exception ex)19 {20 ex.printStackTrace();21 con.rollback(svpt);22 }23     finally
24 {25         con.setAutoCommit(true);26 showUser(st);27         if (st != null) st.close();28         if (con != null) con.close();29 }30 }

  执行结果如下:

=====Simple Transaction test=====com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry'13' for key 'PRIMARY'at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665)at com.mysql.jdbc.Connection.execSQL(Connection.java:3170)at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1316)at com.mysql.jdbc.Statement.executeUpdate(Statement.java:1235)at sample.jdbc.mysql.ResultSetSample.transactionTest2(ResultSetSample.java:185)at sample.jdbc.mysql.ResultSetSample.main(ResultSetSample.java:18)
ID:1; NAME=Zhang San
ID:2; NAME=TEST
ID:5; NAME=Lei Feng
ID:13; NAME=Xiao Li
ID:14; NAME=Xiao Wang

  可以看到最终事务报出了主键冲突异常,事务回滚,但是依然向数据库中插入了ID为13和14的记录。

  另外,在确定SavePoint后,ID为15的记录并没有被插入,它是通过事务进行了回滚。

转载于:https://www.cnblogs.com/Free-Thinker/p/3443356.html

Java回顾之JDBC相关推荐

  1. java回顾:JDBC、工具类、事务、SQL注入

    目录 1.概念 2.JDBC核心API的介绍 2.1 JDBC四个核心对象 2.2  JDBC访问数据库的步骤 3.JDBC注册驱动 3.1 jdbc测试 3.2 注册驱动 4.获取连接 4.1 AP ...

  2. Java回顾之Spring基础

    这一篇主要讲Spring一些基础的内容. 概述 Spring 是一个非常火的框架,尤其是在Web开发领域,和Struts以及Hibernate构成了SSH三剑客.当时Web开发的另一个组合是LAMP, ...

  3. Java中的JDBC是什么?

    JDBC(Java Data Base Connectivity, Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它有一组用Java语言编写的类和接 ...

  4. JAVA数据库编程(JDBC技术)-入门笔记

    本菜鸟才介入Java,我现在不急着去看那些基本的语法或者一些Java里面的版本的特征或者是一些晋级的知识,因为有一点.Net的OOP编程思想,所以对于Java的这些语法以及什么的在用到的时候在去发现学 ...

  5. [转]理解JNDI中 java:comp/env/jdbc/datasource 与 jdbc...

    为什么80%的码农都做不了架构师?>>>    在描述JNDI,例如获得数据源时,JNDI地址有两种写法,例如同是  jdbc/testDS 数据源: A:        java: ...

  6. Java回顾之多线程同步

    在这篇文章里,我们关注线程同步的话题.这是比多线程更复杂,稍不留意,我们就会"掉到坑里",而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战 ...

  7. java中的JDBC

    Java 是通过 JDBC 技术实现对各种数据库访问的,换句话说,JDBC 充当了 Java 应用程 序与各种不同数据库之间进行对话的媒介. JDBC 是 Java 数据库连接(Java DataBa ...

  8. Java中的JDBC教程

    Java中的JDBC教程 欢迎使用JDBC教程.Java DataBase Connectivity(JDBC)是企业应用程序中使用最广泛的API之一.这是因为大多数应用程序使用某种数据库连接.我最近 ...

  9. 10个问题让你快速避开java中的jdbc常见坑

    摘要:JDBC,即Java Database Connectivity,java数据库连接.是一种用于执行SQL语句的Java API,它是Java中的数据库连接规范. 本文分享自华为云社区<1 ...

最新文章

  1. android webview java_Android Webview中调用本地java方法
  2. 阿里云上测试服务器的搭建
  3. CVE-2016-10229分析
  4. C语言用‘%20‘替换字符串中的所有空格的算法(附完整源码)
  5. STM32速度---网页讲解
  6. RocketMQ实现原理
  7. C语言控制结构程序设计,第3讲 C语言程序的基本控制结构_C语言程序设计(上)_pps_大学课件预览_高等教育资讯网...
  8. MUI 图片上传、预览、删除重选等等实现
  9. [PHP] - 逗号和点号的区别
  10. 数据库笔记06:创建并管理数据表
  11. idea配置jfinal_JFinal 开箱评测,这次我是认真的
  12. 银行计算机储蓄系统程序流程图,银行储蓄系统流程图
  13. 大数据平台目前存在的问题
  14. Idea 工具在java文件中怎么避免 import .*包
  15. jetty jndi mysql_jetty配置jndi数据源
  16. navision系统和sap区别_MES与EPR进行系统集成的实际案例-系统接口、交互数据分析...
  17. 基于VS + Qt编程的UG/NX二次开发
  18. 网络编程之OSI七层模型,讲解tcp/ip五层涉及的网络协议,网络通信实现,结合协议来看网络通信流程...
  19. python xlwt 设置表格的行高方法
  20. 动手组装一台 macbook pro 15寸(a1398模具,rmbp mjlq2/mjlt2)

热门文章

  1. Packet for query is too large (12164278 > 4194304). You can change this value
  2. C# List的方法和属性
  3. java虚拟机之虚拟机类加载机制
  4. WordPress 安装插件导致 HTTP 500 内部服务器错误的问题
  5. spring 安全模块在jsp中误用引起的问题
  6. SQL Server监控全解析
  7. 蓝桥杯“基础练习:查找整数
  8. X86汇编语言从实模式到保护模式17:协同式任务切换
  9. 【实用工具】windows/linux下时间统计函数
  10. linux启动本地远程服务,如何使用SSH在本地控制远程服务器执行命令