JDBC Java数据库连接
(Java Database Connectivity)
JDBC本质
本质是sun公司制作的一套操作所有关系型数据库的规则,即接口。各个数据库厂商负责实现这些接口,提供响应的数据库驱动jar包,我们可以使用这套接口(JDBC)编程,最终真正执行的是数据库驱动jar包中的实现类
基本流程
- 导入驱动jar包
- 在项目中新建libs目录(和src同级)
- 将mysql-connector-java-8.0.20.jar复制到libs目录中
- 右键libs目录,将该目录添加到library(add as library)
- 注册驱动
- 获取数据库连接对象Connection
- 定义sql
- 获取执行sql语句的对象statement
- 执行sql,接收返回结果
- 处理结果
- 释放资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class JDBCDemo1 {
public static void main(String[] args) throws Exception { Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection= DriverManager.getConnection("jdbc:mysql://cdb-cd3ybvc6.cd.tencentcdb.com:10056/weixinNews","root","renboyu"); String sql="SELECT * FROM WEIBO WHERE TITLE LIKE '%韩国%';"; Statement statement=connection.createStatement(); ResultSet set=statement.executeQuery(sql); while (set.next()){ String title=set.getString("TITLE"); System.out.println(title); } statement.close(); connection.close(); } }
|
更规范的流程
(尽量避免直接抛出错误)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class JDBCDemo2 {
public static void main(String[] args) { Connection connection=null; Statement statement=null; try { Class.forName("com.mysql.cj.jdbc.Driver"); String sql="insert into stuMess VALUES(null,'Leslie','CS','95');"; connection= DriverManager.getConnection("jdbc:mysql://cdb-cd3ybvc6.cd.tencentcdb.com:10056/jdbcTest","root","renboyu010214"); statement=connection.createStatement(); int result=statement.executeUpdate(sql); System.out.println(result); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally { if(statement!=null) { try { statement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(connection!=null) { try { connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
}
}
|
各个对象详解
DriverManager
驱动管理对象
功能
注册驱动
DriverManager提供registerDriver方法注册给定的驱动程序,而我们在上面代码中所写的Class.forName("com.mysql.cj.jdbc.Driver");
之所以能注册驱动,是因为将com.mysql.cj.jdbc.Driver加载进了内存,而com.mysql.cj.jdbc.Driver包内存在静态代码块,通过阅读源码可以找到该静态代码块
1 2 3 4 5 6 7
| static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
|
可以看到Class.forName("com.mysql.cj.jdbc.Driver");
仍然是通过调用DriverManager提供的registerDriver方法注册驱动程序,只是这种写法比调用方法更加简洁
不过,自5版本后,jar包会自动帮我们注册驱动,所以其实注册驱动步骤可以省略
获取数据库连接
利用DriverManager的getConnection方法可以获取数据库连接,返回数据库连接对象
该方法接收三个参数,分别是
- url:指定连接路径,以MySQL为例:jdbc:mysql://ip地址(域名):端口号/数据库名称
- user:用户名
- password:密码
Connection
数据库连接对象
功能
获取执行sql语句的对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
管理事务
- 开启事务:void setAutoCommit(boolean autoCommit) 调用该方法,设置参数为false,即可开启事务
- 提交事务:void commit()
- 回滚事务:void rollback()
Statement
执行sql语句的对象
功能
执行sql语句
- boolean execute(String sql) 执行任意的sql语句,不常用(返回值为执行的结果)
- int executeUpdate(String sql) 执行DML语句和DDL语句。返回值为影响的行数,可以作为判断执行成功与否的标准
- ResultSet executeQuery(String sql) 执行DQL语句
ResultSet
数据库结果集对象
- boolean next() 游标向下移动一行,返回值表示当前行是否是最后一行数据,如果是则返回false,所以可以用while循环遍历ResultSet
- getString(),getInt,getDouble… 获取某一行中的数据,可以接收两种参数,整型参数表示数据的列数,字符串型数据表示列的名称
PreparedStatement
执行sql语句的对象
sql注入问题
在拼接sql时,有一些sql的特殊关键字参与字符串拼接,导致安全性问题。例如,下面代码
1 2
| String userName, password; String sql="SELECT * FROM loginMess where userName ='"+userName+"' and password='"+password+"';";
|
假如password处用户传入a' or 'a'='a'
。则整个sql语句变为了SELECT * FROM loginMess where userName ='userName' and password='a' or 'a'='a';
则整个sql语句变为恒等句,用户始终可以登录成功
可能发生sql诸如的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
public class LoginDemo2 {
public static void login(String userName,String password){ Connection connection=null; Statement statement=null; try { connection= JDBCUtils.getConnection(); String sql="SELECT * FROM loginMess where userName ='"+userName+"' and password='"+password+"';"; statement=connection.createStatement(); ResultSet set=statement.executeQuery(sql); if (set.next()){ System.out.println("登陆成功"); }else { System.out.println("登陆失败"); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtils.closeDB(connection,statement); }
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in); System.out.println("please input the username:"); String userName=sc.nextLine(); System.out.println("please input the password:"); String password=sc.nextLine(); login(userName,password);
} }
|
解决方案
使用PreparedStatement对象来执行sql语句,PreparedStatement对象执行预编译的sql语句,所有参数使用“?”作为占位符。借此可解决sql诸如问题
使用PreparedStatement后的流程
- 导入驱动jar包
- 注册驱动
- 获取数据库连接对象Connection
- 定义sql
- 获取执行sql语句的对象PreparedStatement(需要传入sql语句)
- 给?赋值
- setInt,setDouble等等方法,第一个参数为通配符?的位置,第二个参数为传入的值
- 执行sql,接收返回结果(PreparedStatement对象的执行方法不需要传入sql语句,因为已经在定义时传入了)
- 处理结果
- 释放资源(PreparedStatement和Statement一样也需要释放)
使用PreparedStatement修改后的登录代码
可以避免sql诸如问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
public class LoginDemo2 {
public static void login(String userName,String password){ Connection connection=null; PreparedStatement preSta=null; ResultSet set=null; try { connection= JDBCUtils.getConnection(); String sql="SELECT * FROM loginMess where userName =? and password=?;"; preSta=connection.prepareStatement(sql); preSta.setString(1,userName); preSta.setString(2,password); set=preSta.executeQuery(); if (set.next()){ System.out.println("登陆成功"); }else { System.out.println("登陆失败"); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtils.closeDB(set,connection,preSta); }
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in); System.out.println("please input the username:"); String userName=sc.nextLine(); System.out.println("please input the password:"); String password=sc.nextLine(); login(userName,password);
} }
|
定义JDBC工具类简化代码
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
public class JDBCUtils {
private static String url; private static String user; private static String password; private static String driver;
static { try { Properties pro=new Properties(); ClassLoader classLoader=JDBCUtils.class.getClassLoader(); URL res=classLoader.getResource("jdbc.properties"); String path=res.getPath(); pro.load(new FileReader(path));
url=pro.getProperty("url"); user=pro.getProperty("user"); password=pro.getProperty("password"); driver=pro.getProperty("driver");
Class.forName(driver); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }
public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,user,password); }
public static void closeDB(ResultSet rs,Connection connection,Statement statement){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
if(statement!=null){ try { statement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
if(connection!=null){ try { connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
}
public static void closeDB(Connection connection,Statement statement){
if(statement!=null){ try { statement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
if(connection!=null){ try { connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
}
}
|
配置文件
1 2 3 4
| url=jdbc:mysql: user=root password=rby driver=com.mysql.cj.jdbc.Driver
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class JDBCDemo3 {
public static void main(String[] args) { Connection connection=null; Statement statement=null; try { connection= JDBCUtils.getConnection(); String sql="SELECT * FROM WEIBO WHERE TITLE LIKE '%韩国%';"; statement=connection.createStatement(); ResultSet set=statement.executeQuery(sql); while (set.next()){ String title=set.getString("TITLE"); System.out.println(title); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { JDBCUtils.closeDB(connection,statement); }
} }
|