JDBC概念
JDBC(Java DateBase Connectivity),java语言连接数据库。
JDBC是SUN公司制定的一套接口,用来连接不同的数据库。
jdbc编程六步
1、注册驱动
2、连接数据库
3、创建数据库操作对象
4、执行SQL语句
5、查询结果集
6、关闭连接
注册驱动
Driver driver = new com.mysql.jdbc.Driver();//创建mysql数据库驱动对象
DriverManager.registerDriver(driver);//注册驱动
现在已经不用该种方式注册驱动,因为数据库java文件中com.mysql.jdbc.Driver这个这个类已经通过静态代码块自动注册了驱动。
当我们使用Class.forName()方法获取这个类时,com.mysql.jdbc.Driver类会自动加载静态代码块注册驱动。
Class.forName("com.mysql.jdbc.Driver");
连接数据库
Connection conn =DriverManager.getConnection
("jdbc:mysql://localhost:3306/jdbc","root","123456");
创建数据库操作对象
Statement stmt = conn.createStatement();
执行SQL语句
String sql="select ename,deptno from emp;";
ResultSet rs = stmt.executeQuery(sql);
查询结果集
while (rs.next()){
String s1 = rs.getString(1);//获取第一个查询字段,ename
String s2 = rs.getString(2);//获取第二个查询字段,deptno
System.out.println(s1+" "+s2);
}
关闭连接
finally {
if (rs != null) {//关闭ResultSet结果集
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {//关闭操作对象
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {//关闭连接
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
以上六步是正常的JDBC执行流程。
但是此种书写步骤可能会造成sql注入,因为用户可以参与sql语句的编写。
在用户传入编写的语句后,程序才会编译sql语句并执行。
SQL注入
用户参与编写sql语句,导致sql注入。
import java.sql.*;
import java.util.HashMap;
import java.util.Scanner;
public class JDBCTest2 {
public static void main(String[] args) {
HashMap<String,String> initui = initui();
String admin = initui.get("user");
String password = initui.get("password");
jdbcConnection(admin,password);
}
private static HashMap initui() {//初始化用户界面,让用户输入参数
System.out.println("------------------用户登录界面--------------------");
Scanner s = new Scanner(System.in);
System.out.println("请输入用户名:");
String user = s.nextLine();
System.out.println("请输入密码:");
String password = s.nextLine();
HashMap<String, String> hashMap = new HashMap<>();//将用户输入的参数存入到map集合
hashMap.put("user",user);
hashMap.put("password",password);
return hashMap;
}
private static void jdbcConnection(String user, String password){//用JDBC连接数据库
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","123456");
------------------------------------------------------------------------------ //先进行sql语句的书写,再进行编译,造成sql注入
stmt = conn.createStatement();
String sql="select*from user_login where user='"+user+"' and password='"+password+"'";
System.out.println(sql);
rs = stmt.executeQuery(sql);
------------------------------------------------------------------------------
if(rs.next())
System.out.println("登陆成功");
else
System.out.println("登录失败");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/* ------------------用户登录界面--------------------sql注入演示
请输入用户名:
ad
请输入密码:
ad' or 'ad'='ad
select*from user_login where user='ad' and password='ad' or 'ad'='ad'
登陆成功*/
此时我们可以使用prepareStatement对象来预防这种情况。PreparedStatement对象允许数据库预编译SQL语句,然后再让用户传值。
import java.sql.*;
import java.util.HashMap;
import java.util.Scanner;
public class JDBCTest3 {
public static void main(String[] args) {
HashMap<String,String> initui = initui();
String admin = initui.get("user");
String password = initui.get("password");
jdbcConnection(admin,password);
}
private static HashMap initui() {//初始化用户界面,让用户输入参数
System.out.println("------------------用户登录界面--------------------");
Scanner s = new Scanner(System.in);
System.out.println("请输入用户名:");
String user = s.next();
System.out.println("请输入密码:");
String password = s.next();
HashMap<String, String> hashMap = new HashMap<>();//将用户输入的参数存入到map集合
hashMap.put("user",user);
hashMap.put("password",password);
return hashMap;
}
private static void jdbcConnection(String user, String password){//用JDBC连接数据库
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","123456");
------------------------------------------------------------------------------
// 为防止sql注入,先编译sql语,再进行传值。'?'是占位符,调用操作对象的set方法,为其传值,1代表第一个占位符,2代表第二个占位符
String sql="select*from user_login where user=? and password=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1,user);
pstmt.setString(2,password);
rs = pstmt.executeQuery();
-----------------------------------------------------------------------------
if(rs.next())
System.out.println("登陆成功");
else
System.out.println("登录失败");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
prepareStatement对象优点在于能预编译sql语句,编译后,再让用户传值,可以有效防止用户进行sql注入。
statement对象优点在于用户能参与sql语句字符串拼接,但是要注意限制拼接的内容。否则会造成sql注入。
JDBC对数据库表进行增删改
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JDBCTest4 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn=null;
PreparedStatement pstmt=null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","123456");
/*
System.out.println("-----------增--------------");
String sql="insert into emp(id,name,dept) value(?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,1);
pstmt.setString(2,"wangwu");
pstmt.setString(3,"策划部");
pstmt.execute();*/
/*System.out.println("----------改-----------------");
String sql="update emp set name=?,dept=? where id =?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1,"zhaosi");
pstmt.setString(2,"研发部");
pstmt.setInt(3,1);
pstmt.executeUpdate();
*/
System.out.println("----------------删----------------------");
String sql="delete from emp where id=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,1);
pstmt.execute();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
JDBC对数据库事务处理
JDBC默认自动提交事务。
当我们需要关闭事务的自动提交时,使用conn.setAutoCommit(false)。
当我们的事务执行完成,使用conn.commit(),提交事务。
在抛出的异常中放置 conn.rollback(),确保出现异常可以回滚。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JDBCTest5 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc","root","123456");
conn.setAutoCommit(false);//将事务的自动提交置为flase
String sql = "update account set balance=? where actno=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,30000);
pstmt.setString(2,"1");
int i = pstmt.executeUpdate();
Thread.sleep(1000*10);//模拟网络延迟
pstmt.setInt(1,20000);
pstmt.setString(2,"2");
i+= pstmt.executeUpdate();//判断是否更新了两次
if(i==2)
System.out.println("转账成功");
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
if (conn != null) {
conn.rollback();//如果抛出异常要进行回滚
}
} catch (SQLException ex) {
ex.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
JDBCUtil工具类
JDBCUtil可以将我们经常重复写的代码进行封装,提升编程效率。
JDBC编程六步(使用Util工具类后),大大简化了代码。
import utils.DBUtil;
import java.sql.*;
public class JDBCTest6 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt =null;
ResultSet rs=null;
try {
conn = DBUtil.connection();//调用工具类注册驱动,连接数据库
String sql="select actno,balance from account";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString(1)+","+rs.getInt(2));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(rs,pstmt,conn);//关闭连接
}
}
}
JDUCUtil工具类
package utils;
import java.sql.*;
import java.util.ResourceBundle;
public class DBUtil {
private DBUtil(){}
private static ResourceBundle bundle = ResourceBundle.getBundle("Resourse//jdbc");//从配置文件中获取数据库相关信息
static {//注册驱动
try {
Class.forName(bundle.getString("Driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection connection() throws SQLException {//创建连接
Connection conn = DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),bundle.getString("password"));
return conn;//返回连接
}
public static void close(ResultSet rs,Statement stmt,Connection conn){//关闭所有连接
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
properties配置文件
Driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbc
user=root
password=123456