1、JDBC 工作原理 2、常用接口JDBC是什么?JDBC英文名为:Java Data base Connectivity(Java数据库连接),官方解释它是Java编程语言和广泛的数据库之间独立于数据库的连接标准的Java API,根本上说JDBC是一种规范,它提供的接口,一套完整的,允许便捷式访问底层数据库。可以用JAVA来写不同类型的可执行文件:JAVA应用程序、JAVA Applets、Java Servlet、JSP等,不同的可执行文件都能通过JDBC访问数据库,又兼备存储的优势。简单说它就是JAVA与数据库的连接的桥梁或者插件,用JAVA代码就能操作数据库的增删改查、存储过程、事务等。
提供的接口包括:JAVA API:提供对JDBC的管理链接;JAVA Driver API:支持JDBC管理到驱动器连接。 DriverManager:这个类管理数据库驱动程序的列表,查看加载的驱动是否符合JAVA Driver API的规范。 Connection:与数据库中的所有的通信是通过唯一的连接对象。 Statement:把创建的SQL对象,转而存储到数据库当中。 ResultSet:它是一个迭代器,用于检索查询数据。3、操作流程 3.1 简单实例
public class JDBCdemo {
public static void main(String[] args) throws Exception {
// 注册驱动
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
// mysql 8 之前为 com.mysql.jdbc.Driver
// mysql 8 及之后 com.mysql.jsbc.cj.Driver
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/test_db?serverTimezone=UTC";
String username = "root";
String password = "root123";
// 获取连接对象
Connection connection = DriverManager.getConnection(url,username,password);
//System.out.println(connection); // com.mysql.cj.jdbc.ConnectionImpl@954b04f
// 创建 sql 对象
Statement statement = connection.createStatement();
String sql = "select * from tb_user";
// 执行 sql 查询语句得到结果集
ResultSet resultSet = statement.executeQuery(sql);
// statement.executeUpdate(sql); 执行修改 SQL
while (resultSet.next()){
System.out.println(resultSet.getInt("id"));
System.out.println(resultSet.getString("name"));
}
// 关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
3.2 封装工具类 JDBCUtil.java
public class JDBCUtils {
static String url = "jdbc:mysql://127.0.0.1:3306/hw_db3?serverTimezone=UTC";
static String username = "root";
static String password = "root123";
static {
try{
Class.forName("com.mysql.cj.jdbc.Driver");
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(url, username, password);
}
public static Statement createStatement(Connection conn) throws Exception{
return conn.createStatement();
}
// 关闭连接,释放资源
public static void close(ResultSet rs, Statement st,Connection conn) throws Exception{
if(rs != null){
rs.close();
}
if(st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}
- 通过加载外部文件 db.properties 创建工具类
# 文件中存放如下内容 myDriverClass=com.mysql.cj.jdbc.Driver myUrl=jdbc:mysql://127.0.0.1:3306/hw_db3?serverTimezone=UTC myUsername=root myPassword=root123
public class JDBCUtils {
static Properties p = new Properties();
static {
try{
// 类加载器(得到当前类 在内存中的加载的所有信息)
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
p.load(in);
// 加载驱动
Class.forName(p.getProperty("myDriverClass"));
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(p.getProperty("myUrl"), p.getProperty("myUsername"), p.getProperty("myPassword"));
}
public static Statement createStatement(Connection conn) throws Exception{
return conn.createStatement();
}
// 关闭连接,释放资源
public static void close(ResultSet rs, Statement st,Connection conn) throws Exception{
if(rs != null){
rs.close();
}
if(st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}
4、Statement和Preparement
Statement 对象是用来执行SQL语句的
String sql = "select * from user where id = "+ id +" and username = '"+ username +"'"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql);
PreparedStatement:预编译的Statement对象,是Statement的子接口。
PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet resultSet = preparedStatement.executeQuery();
PreparedStatement 插入100条记录所用的时间比 Statement 插入100条记录所花费时间少。
PreparedStatement 不需要拼接,还可以防止SQL注入从而提高安全性。
String sql = "select * from user where id = ? and username = ?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); // 参数1表示sql语句中的占位符发索引,参数2表示占位符对应的值 // 参数1的索引值一定是从1开始 preparedStatement.setInt(1,4); preparedStatement.setString(2,"小黑"); ResultSet resultSet = preparedStatement.executeQuery();
PreparedStatement相较于Statement有三个好处:
- 预编译,性能较好
- 不用拼接,易编写易读懂
- 防止SQL注入,提高安全性
- 使用 PrearedStatement,可以通过预编译的方式避免在拼接SQL时造成SQL注入。
- 使用ConnectionPool 【连接池】
- 禁用自动提交【手动管理事务】
这个最佳实践在我们使用JDBC的批量提交的时候显得非常有用,将自动提交禁用后,你可以将一组数据库操作放在一个事务中,而自动提交模式每次执行SQL语句都将执行自己的事务,并且在执行结束提交。 - 使用 Batch Update:批量更新/删除,比单个更新/删除,能显著减少数据传输的往返次数,提高性能。
- 使用列名获取 ResultSet 中的数据,从而避免invalidColumIndexError
JDBC中的查询结果封装在ResultSet中,我们可以通过列名和列序号两种方式获取查询的数据,当我们传入的列序号不正确的时候,就会抛出invalidColumIndexException,例如你传入了0,就会出错,因为ResultSet中的列序号是从1开始的。另外,如果你更改了数据表中列的顺序,你也不必更改JDBC代码,保持了程序的健壮性。有一些Java程序员可能会说通过序号访问列要比列名访问快一些,确实是这样,但是为了程序的健壮性、可读性,我还是更推荐你使用列名来访问。 - 使用变量绑定而不是字符串拼接
- 使用 PreparedStatment 可以防止注入,而使用?或者其他占位符也会提升性能,因为这样数据库就可以使用不同的参数执行相同的查询,提示性能,也防止SQL注入。
- 关闭Connection 等资源,确保资源被释放;
- 选择合适的JDBC驱动,参考前文,选择第四种;
尽量使用标准的SQL语句,从而在某种程度上避免数据库对SQL支持的差异
不同的数据库厂商的数据库产品支持的SQL的语法会有一定的出入,为了方便移植,推荐使用标准的ANSI SQL标准写SQL语句。 - 使用正确的getXXX()方法
当从ResultSet中读取数据的时候,虽然JDBC允许你使用getString()和getObject()方法获取任何数据类型,推荐使用正确的getter方法,这样可以避免数据类型转换。



