JDBC
1、数据库驱动
数据库驱动由厂商直接提供,程序通过驱动连接数据库,进行数据的操作。没有驱动,程序无法进行数据库操作
2、JDBC
有了驱动,程序可以对数据库进行操作,但MySQL ,Oracle,SQL Sever 等不同的数据库驱动不同,对于不同的数据库需要编写不同的代码,为了简化开发人员的(对数据库的统一)操作,提供了一个(java操作数据库的)规范,为 JDBC
这些规范是实现由具体的厂商完成
对于开发人员来说,只需要掌握 JDBC 的接口的操作即可
在架构里没有什么是加一层解决不了的
2.1 JDBC操作数据库
导入驱动jar
mysql-connector-java-8.0.18.jar
注意:MySQL不同版本导入不同的驱动jar
package com.json.jdbc;
import java.sql.*;
public class TestJdbc {
private static String url = "jdbc:mysql://127.0.0.1:3306/client?" +
"serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true" ;
private static String username = "root" ;
private static String password = "root123" ;
public static void jdbc() throws SQLException, ClassNotFoundException {
//1、加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接的对象 Connection对象,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3、获取操作数据的对象 Statement、PreparedStatement对象,用于增删改查
Statement statement = connection.createStatement();
//4、执行SQL语句 SQL为查询则返回结果集对象 ResultSet对象,封装了结果集 SQL为增删改则返回受影响的行数int
String sql = "select * from `student` where `id` < 20" ;
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){ //如果resultSet下一行不为空
String name = resultSet.getString("name");
String grate = resultSet.getString("grate");
int age = resultSet.getInt("age");
System.out.println("姓名:"+name+",年级:"+grate+",年龄:"+age);
}
//6、关闭连接,释放资源
resultSet.close();
statement.close();
connection.close();
}
public static void main(String[] args) throws SQLException, ClassNotFoundException {
jdbc();
}
}
2.2 JDBC中对象的解释
DriverManager
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法,加载驱动类
注意:8.0以上版本驱动类为com.mysql.cj.jdbc.Driver,5.0版本驱动类为com.mysql.jdbc.Driver
URL
String url = "jdbc:mysql://localhost:3306/client?"+
"serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true" ;
/*
localhost:主机地址
3306:端口号
client:数据库名
serverTimezone=UTC 指定时区 --8.0以上必写,其他版本可不写
useUnicode=true 是否使用Unicode字符集(可不写)
characterEncoding=utf8 指定字符集(可不写)
useSSL=true 加密数据,防止数据传输途中被窃用(可不写)
*/
Connection 代表数据库的对象
//创建执行SQL的对象Statement、PreparedStatement
Statement statement = connection.createStatement();
String sql = "select * from student where id= ? " ; //预编译
PreparedStatement prep = connection.prepareStatement(sql);
//connection开启事务
connection.setAutoCommit(false);
connection.commit();
connection.rollback();
connection.close();
Statement、PreparedStatement 执行SQL的对象
statement.executeQuery(sql); //查询操作返回ResultSet对象
statement.execute(sql); //执行任何的SQL
statement.executeUpdate(sql); //更新、插入、删除操作,返回受影响的行数int
preparedStatement.executeQuery();//查询操作返回ResultSet对象
preparedStatement.execute();//执行任何的SQL
preparedStatement.executeUpdate();//更新、插入、删除操作,返回受影响的行数int
ResultSet 封装了查询数据的结果集的对象
获得指定的数据类型
resultSet.getObject("字段名"); //可获取任意类型字段的数据
resultSet.getInt("字段名"); //获得int类型字段的数据
resultSet.getString("字段名"); //获得varchar类型字段的数据
resultSet.getFloat("字段名"); //获得float类型字段的数据
resultSet.getDate("字段名"); //获得datetime类型字段的数据
遍历,指针
resultSet.beforeFirst();//移动到最前行
resultSet.afterLast(); //移动到最后行
resultSet.next(); //移动到下一行
resultSet.previous(); //移动到上一行
resultSet.absolute(row); //移动到指定行
代码封装优化
jdbc.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/client?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=root123
JDBCUtil封装加载驱动,获取连接,关闭资源,增删改操作
public class JDBCUtil {
private static String driver = null ;
private static String url = null ;
private static String username = null ;
private static String password = null ;
//在静态代码块中加载配置文件,加载驱动类
static {
try {
InputStream in = JDBCUtil.class.getClassLoader().
getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return Connection
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
/**
* 关闭连接,释放资源
* @param connection
* @param statement
* @param resultSet
*/
public static void release(Connection connection , Statement statement , ResultSet resultSet){
try{
if (resultSet!=null) resultSet.close();
if (statement!=null) statement.close();
if (connection!=null) connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 增删改操作
* @param sql
*/
public static void executeUpdate(String sql){
Connection connection = null ;
Statement statement = null ;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
int effectedNum = statement.executeUpdate(sql);
if (effectedNum>0){
System.out.println("更新成功!!!");
}
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtil.release(connection,statement,null);
}
}
}
查询
public JDBC{
public static void jdbc_select(){
Connection connection = null ;
Statement statement = null ;
ResultSet resultSet = null ;
try {
connection = JDBCUtil.getConnection();
statement = connection.createStatement();
String sql = "select * from `student` where `id` < 10" ;
resultSet = statement.executeQuery(sql);
while (resultSet.next()){
String name = resultSet.getString("name");
String grate = resultSet.getString("grate");
int age = resultSet.getInt("age");
System.out.println("姓名:"+name+",年级:"+grate+",年龄:"+age);
}
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtil.release(connection,statement,resultSet);
}
}
public static void main(String[] args){
jdbc_select() ;
}
}
插入
public JDBC{
public static void jdbc_insert(){
String sql = "insert into `student` (`name`,`grate`,`age`,`sex`) "+
"values ('json','大一',20,0)" ;
JDBCUtil.executeUpdate(sql);
}
public static void main(String[] args){
jdbc_insert();
}
}
更新
public JDBC{
public static void jdbc_insert(){
String sql = "update `student` set `name`='json' where `id` = 1000 ";
JDBCUtil.executeUpdate(sql);
}
public static void main(String[] args){
jdbc_insert();
}
}
删除
public JDBC{
public static void jdbc_insert(){
String sql = "delete from `student` where `id` = 1000 ";
JDBCUtil.executeUpdate(sql);
}
public static void main(String[] args){
jdbc_insert();
}
}
3、SQL注入
SQL注入攻击是通过操作输入来修改SQL语句,用以达到执行代码对WEB服务器进行攻击的方法。
SQL注入(有意拼接字符串,达到不需要条件即可随意操作数据库)
//用户登录操作正常逻辑,用户名为json,密码为*****
String name ="json" ;
String password="*****" ;
String sql
= "select * from `user` where `name`='"+name+"' and `password` ='"+password+"'";
//如果存在该用户则登录成功
//SQL注入(有意拼接字符串,达到不需要条件即可随意操作数据库)
String name = "任意字符串" + " ' or 1=1 -- ";
String password = "***** " ;
String sql
= "select * from `user` where `name`='"+name+"' and `password` ='"+password+"'";
/*
完整的语句就变为:
select * from user where name='任意字符串' or 1=1 -- ' and password = '*****' ;
1=1为所有条件皆成立
--后面为注释,直接忽略了密码
*/
注意:Statemen不能防止SQL注入,在开发中不可用,PreparedStatement可以防止SQL注入,在开发中推荐使用
4、PreparedStatement对象
PreparedStatement
public class TestJdbc {
private static String url = "jdbc:mysql://127.0.0.1:3306/client?" +
"serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true" ;
private static String username = "root" ;
private static String password = "root123" ;
public static void jdbc() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);
//先预编译SQL,使用占位符?表示将要输入的值
String sql = "select * from `student` where `id` < ? and `age` > ?" ;
//获取PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给占位符设置值
preparedStatement.setObject(1,10); //第一个占位符设置值为10
preparedStatement.setInt(2,3); //第二个占位符设置值为3
ResultSet resultSet = preparedStatement.executeQuery();
while(resultSet.next()){ //如果resultSet下一行不为空
String name = resultSet.getString("name");
String grate = resultSet.getString("grate");
int age = resultSet.getInt("age");
System.out.println("姓名:"+name+",年级:"+grate+",年龄:"+age);
}
//6、关闭连接,释放资源
resultSet.close();
statement.close();
connection.close();
}
public static void main(String[] args) throws SQLException, ClassNotFoundException {
jdbc();
}
}
5、JDBC操作事务
要么都成功,要么都失败
ACID原则
-
原子性:要么全部完成,要么全部不完成
-
一致性:总数不变
-
隔离性:一个事务不能影响另一个事务
-
持久性:提交后,数据持久化,任何操作都无法再影响到事务
事务
public class TestJdbc {
private static String url = "jdbc:mysql://127.0.0.1:3306/client?" +
"serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true" ;
private static String username = "root" ;
private static String password = "root123" ;
public static void jdbc() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);
PreparedStatement preparedStatement = null ;
try{
//1、开启事务,设置autoCommit为false
connection.setAutoCommit(false) ;
//2、操作事务
//2.1 扣钱
String sql1="update `account` set `money`=`money`-200 where `id`=1 " ;
preparedStatement = connection.prepareStatement(sql1);
//2.2加钱
preparedStatement.executeUpdate();
String sql2="update `account` set `money`=`money`+200 where `id`=2 " ;
preparedStatement = connection.prepareStatement(sql2) ;
preparedStatement.executeUpdate();
//3、提交事务
connection.commit();
}catch( Exception e ){
//4、失败,回滚事务
connection.rollback();
}finally{
//5、释放资源
preparedStatement.close();
connection.close();
}
}
public static void main(String[] args) throws SQLException, ClassNotFoundException {
jdbc();
}
}