一.JDBC是什么,它有什么作用
当我们学习了Java和MySQL数据库后,如何通过Java代码去操作数据库内的数据呢?这就用到了JDBC,JDBC是SUN公司提供的一套接口,面向接口编程给我们带来了很大的遍历,只需要不同的数据库厂商对该接口进行实现即可,当不同数据库厂商实现了JDBC接口后,我们只需要调用接口内的方法,而不需要关注不同数据库厂商底层的实现方法,带来了很大的遍历。
编写代码模拟JDBC的实现过程
public interface JDBCTest {
//模拟SUN公司提供的JDBC接口
public void getConn();
}
/*****************************************************/
public class MySQLTest implements JDBCTest{
//模拟MySQL厂商的底层实现
@Override
public void getConn() {
System.out.println("连接到MySQL数据库");
}
}
/******************************************************/
public class OracleTest implements JDBCTest {
//模拟Oracle厂商的底层实现
@Override
public void getConn() {
System.out.println("连接到Oracle数据库");
}
}
/*******************************************************/
public class ConnMySQL {
public static void main(String[] args) {
//模拟我们程序员对接口进行调用
JDBCTest jdbcTest1 = new MySQLTest();
JDBCTest jdbcTest2 = new OracleTest();
}
}
二.JDBC的基本应用
JDBC的实现,主要分为以下几个步骤
1.注册DriverManager驱动
2.获取与数据库的链接Connection
3.创建执行SQL语句的对象Statement
4.执行SQL语句,如果是查询语句的话,返回结果集ResultSet
5.处理结果集ResultSet
6.关闭连接,由小到大 ResultSet,Statement,Connection
代码如下
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注册驱动 注意这里的Driver()包导的是mysql厂商提供的包
DriverManager.registerDriver(new Driver());
//2.获得连接 三个参数分别为数据库的url 数据库用户名 数据库密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "123456");
//3.创建执行SQL语句的Statement对象
Statement st = conn.createStatement();
//4.执行SQL语句
ResultSet rs = st.executeQuery("SELECT * FROM cl");
//5.处理结果集
while (rs.next()){
//下标是从1开始的,也可以根据字段名取出数据
int id = rs.getInt(1);
//int id2 = rs.getInt("cid");
System.out.println(id);
}
//6.关闭连接,从小到大
rs.close();
st.close();
conn.close();
}
}
三.代码中异常的处理以及工具类和配置文件的封装
由于在上述代码中,没有对异常进行处理,直接将异常抛出给调用它的方法,所以我们自己进行处理,而且在连接的获取和URL,姓名,密码的过程中,代码是固定的,所以我们将它单独封装出来,这样不仅会降低程序的耦合度,也大大降低了程序的复杂度。
/********************配置文件db.properties************************/
DRIVERNAME=com.mysql.jdbc.Driver
URL=jdbc:mysql://localhost:3306/mysql
USERNAME=root
PASSWORD=123456
/********************封装工具类JdbcUtils**************************/
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
public static String drivername ;
public static String url ;
public static String userName ;
public static String passWord ;
static {
Properties properties = new Properties();
InputStream in = JDBCDemo2.class.getClassLoader().getResourceAsStream("Resources/db.properties");
try {
properties.load(in);
drivername = properties.getProperty("DRIVERNAME");
url = properties.getProperty("URL");
userName = properties.getProperty("userName");
passWord = properties.getProperty("passWord");
//为什么使用反射而不是DriverMangager.Register() 因为后者会注册两次驱动
Class.forName(drivername);
} catch (Exception e) {
e.printStackTrace();
}
}
//这个方法用来获得与数据库的连接
public static Connection getConn() throws Exception {
return DriverManager.getConnection(url, userName, passWord);
}
public static void release(ResultSet rs,Statement st,Connection conn){
try {
if(rs!=null){
rs.close();
rs=null;
//垃圾回收器会马上回收
}
}catch (Exception e ){
e.printStackTrace();
}
try {
if(st!=null){
st.close();
st=null;
//垃圾回收器会马上回收
}
}catch (Exception e ){
e.printStackTrace();
}
try {
if(conn!=null){
conn.close();
conn=null;
//垃圾回收器会马上回收
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
/********************主类JdbcDemo2**************************/
import com.mysql.jdbc.Driver;
import javax.sql.rowset.JdbcRowSet;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class JDBCDemo2 {
public static void main(String[] args) {
Connection conn =null;
Statement st = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConn();
st = conn.createStatement();
rs = st.executeQuery("SELECT * FROM cl");
while (rs.next()){
int id = rs.getInt(1);
}
JDBCUtils.release(rs,st,conn);
}catch (Exception e ){
e.printStackTrace();
}finally {
JDBCUtils.release(rs,st,conn);
}
}
}
四.登录案例和SQL注入现象的演示以及解决
登录案例
用JDBC模拟一个登录的案例,首先数据库中要有一个用户信息表。
CREATE TABLE user_info(
name varchar(255),
password varchar(255)
);
INSERT INTO user_info VALUES('zs','123456'),('ls','888888');
主类代码如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCDemo3 {
public static void main(String[] args) {
Connection conn =null;
Statement st =null;
ResultSet rs = null;
try {
//1.获取与数据库的连接
conn = JDBCUtils.getConn();
//2.让用户自己输入账号和密码,并接收为参数
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String userName = sc.nextLine();
System.out.println("请输入密码");
String passWord = sc.nextLine();
//3.获得SQL语句的执行对象
st = conn.createStatement();
//字符串类型要自己加单引号,st不能自动添加
rs = st.executeQuery("SELECT * FROM user_info WHERE name='" + userName + "AND password=" + passWord + "'");
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.release(rs,st,conn);
}
}
}
SQL注入现象
在上述的代码中,如果我们在输入密码时输入'1asd' or '1' ='1 依然会登陆成功,效果如下图
首先我们要知道产生这个现象的原因是什么,当我们输入的字符串拼接到SQL语句上时,是下面这样的
SELECT * FROM user_info WHERE name='asd' AND password='lasd' or '1'='1'
我们可以看出来,产生SQL注入现象的原因有两个
1.我们输入的字符串中有SQL关键字
2.更重要的,DBMS将我们输入的关键字编译了
解决方法如下:
既然我们的关键字被DBMS编译了,我们就解决这个问题,把Statement对象换成PreparedStatement
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class JDBCDemo3 {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement pst =null;
ResultSet rs = null;
try {
//1.获取与数据库的连接
conn = JDBCUtils.getConn();
//2.让用户自己输入账号和密码,并接收为参数
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String userName = sc.nextLine();
System.out.println("请输入密码");
String passWord = sc.nextLine();
//3.获得SQL语句的执行对象
//Statement st = conn.createStatement();
//PreparedStatement会对SQL语句进行预编译
pst = conn.prepareStatement("SELECT * FROM user_info WHERE name=? AND password=?");
//设置账号和密码,下标从1开始
//如果是字符串类型的话,会在赋值的时候自动加单引号
pst.setString(1,userName);
pst.setString(2,passWord);
//执行
rs = pst.executeQuery();
//字符串类型要自己加单引号,st不能自动添加
//ResultSet rs = st.executeQuery("SELECT * FROM user_info WHERE name='" + userName + "AND password=" + passWord + "'");
if (rs.next()){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.release(rs,pst,conn);
}
}
}
五.JDBC演示MySQL的事务
数据库中的事务是指对数据库执行一批操作,这些操作最终要么全部执行成功,要么全部
失败,不会存在部分成功的情况。
举个例子
⽐如A用户给B用户转账100操作,过程如下:
1.从A账户扣100
2.给B账户加100
如果在事务的支持下,上⾯最终只有2种结果:
1. 操作成功:A账户减少100;B账户增加100
2. 操作失败:A、B两个账户都没有发⽣变化
如果没有事务的支持,可能出现错:A账户减少了100,此时系统挂了,导致B账户没有加
上100,A账户凭空少了100