Java之JDBC

java

JDBC的全称为:Java DataBase Connectivity(Java数据库连接)。
是一种执行SQL语句的Java API,可以为多种关系型数据库提供统一的访问。

1.JDBC的API

(1)JDBC入门

package com.imooc.jdbc.demo1;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;

public class JDBCDemo1 {

public void demo1() throws SQLException { //这里需要接受异常

//1.加载驱动

DriverManager.registerDriver(new Driver());

//2.获取连接

Connection conn = DriverManager.getConnection("jdbc:mysql://18.0.51.10:3306/jdbctest","root","123456");

//3.创建执行SQL语句的对象

String sql = "select * from user";

Statement stmt = conn.createStatement();

//4.执行sql语句

ResultSet resultSet = stmt.executeQuery(sql);

while (resultSet.next()){

int uid = resultSet.getInt("uid");

String name = resultSet.getString("name");

String mobile = resultSet.getString("mobile");

String addr = resultSet.getString("addr");

System.out.println(uid+" "+name+" "+mobile+" "+addr);

}

//5.释放资源

resultSet.close();

stmt.close();

conn.close();

}

}

如果数据库中文变成???,需要注意编码方式:
"jdbc:mysql://18.0.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8"

(2)JDBC的API——DriverManager的使用

DriverManager属于驱动管理类。
主要有两个作用:
a.注册驱动
DriverManager.registerDriver(new Driver());
但是这种方式会导致驱动注册两次。
因为在这个驱动中有一个静态代码块会注册驱动。所以更好的做法是加载静态代码块。
实际中会使用如下方式注册:
Class.forName("com.mysql.cj.jdbc.Driver");

b.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest","root","123456");
jdbc:协议
mysql:子协议

(3)JDBC的API——Connection的使用

Connection主要用来连接对象。
主要作用:
a.创建执行SQL语句的对象
  createStatement():创建一个Statement对象来将SQL语句发送到数据库。(执行SQL语句)
  prepareStatement(String sql): 创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。(预编译SQL语句)
  prepareCall(String sql):创建一个CallableStatement对象来调用数据库存储过程。(执行SQL中的存储过程)

b.进行事务的管理
  setAutoCommit():将此连接的自动提交模式设置为给定状态。
  commit():提交事务。
  rollback():回滚

(4)JDBC的API——Statement的使用

Statement主要用来执行SQL语句。
a.执行SQL语句
  execute(String sql):执行SQL,执行select返回true,否则返回false
  executeQuery(String sql):执行SQL中的select语句,返回一个结果集
  executeUpdate(String sql):执行SQL中的insert/update/delete语句,返回一个int类型的值
b.执行批处理操作
  addBatch(String sql):添加到批处理
  executeBatch():执行批处理
  clearBatch():清空批处理

(5)JDBC的API——ResultSet的使用

ResultSet,结果集,就是查询语句接口的封装。
next():将光标从当前位置向前移动,也就是下一个值。
针对不同的类型的数据可以使用getXXX()获取数据。通用获取数据的方法getObject()。

(6)JDBC的资源释放

jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象。
这些对象通常是ResultSet,Statement和Connection对象。

每个数据库都有最大连接数,如果没有释放,可能导致无法建立新的数据库连接。
特别是Connection对象,它是非常稀有的资源,用完必须马上释放,
如果COnnection不能及时、正确的关闭,极易导致系统宕机。
Connection的使用原则是尽量晚创建,尽量早的释放。

常规释放方式:

  resultSet.close();
  stmt.close();
  conn.close();

但是这种释放方式并不彻底,如果前面代码异常,那么可能无法得到释放。可以使用try-finally关键字:

package com.imooc.jdbc.demo1;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;

public class JDBCDemo1 {

public void demo1() { //这里需要接受异常

Connection conn = null;

Statement stmt = null;

ResultSet resultSet = null;

try {

//1.加载驱动

// DriverManager.registerDriver(new Driver());

Class.forName("com.mysql.cj.jdbc.Driver");

//2.获取连接

conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest", "root", "123456");

//3.创建执行SQL语句的对象

String sql = "select * from user";

stmt = conn.createStatement();

//4.执行sql语句

resultSet = stmt.executeQuery(sql);

while (resultSet.next()) {

int uid = resultSet.getInt("uid");

String name = resultSet.getString("name");

String mobile = resultSet.getString("mobile");

String addr = resultSet.getString("addr");

System.out.println(uid + " " + name + " " + mobile + " " + addr);

}

} catch (Exception e) {

e.printStackTrace();

} finally { //不论结果如何都会释放连接

//5.释放资源

if (resultSet != null){ //需要对情况进行判断,如果可能没有创建连接,当然也无法释放连接

try {

resultSet.close();

}catch (SQLException e){

e.printStackTrace();

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException e){

e.printStackTrace();

}

stmt = null;

}

if (conn != null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

conn = null; //垃圾回收机制更早回收对象,提前回收

}

}

}

}

2.JDBC的CRUD操作

所谓的CRUD就是数据库的增删改查。

(1)增删改

package com.imooc.jdbc.demo1;

import org.junit.Test;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

public class JDBCDemo2 {

@Test

public void demo2(){

Connection conn = null;

Statement stmt = null;

try {

Class.forName("com.mysql.cj.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8", "root", "123456");

//增

//String sql = "insert into user value(null,'hao','18972068500','湖北安陆')";

//改

//String sql = "update user set mobile='15302723629' where name='ming'";

//删

String sql = "delete from user where name='xing'";

stmt = conn.createStatement();

int i = stmt.executeUpdate(sql);

if (i > 0){

System.out.println("删除成功");

}

} catch (Exception e) {

e.printStackTrace();

} finally {

if (stmt != null) {

try {

stmt.close();

} catch (SQLException e){

e.printStackTrace();

}

stmt = null;

}

if (conn != null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

conn = null;

}

}

}

}

(2)查

a.查询多条记录

package com.imooc.jdbc.demo1;

import org.junit.Test;

import java.sql.*;

public class JDBCDemo2 {

@Test

public void demo2(){

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

Class.forName("com.mysql.cj.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8", "root", "123456");

String sql = "select * from user";

stmt = conn.createStatement();

rs = stmt.executeQuery(sql);

while (rs.next()){

int uid = rs.getInt("uid");

String name = rs.getString("name");

String mobile = rs.getString("mobile");

String addr = rs.getString("addr");

System.out.println(uid+" "+name+" "+mobile+" "+addr);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

if (rs != null) {

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

rs = null;

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException e){

e.printStackTrace();

}

stmt = null;

}

if (conn != null){

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

conn = null;

}

}

}

}

b.查询单条记录

if (rs.next()){

int uid = rs.getInt("uid");

String name = rs.getString("name");

String mobile = rs.getString("mobile");

String addr = rs.getString("addr");

System.out.println(uid+" "+name+" "+mobile+" "+addr);

}

3.JDBC工具类的抽取

为了简化JDBC的开发,可以将一些重复的代码进行提取。

(1)抽象工具类

package com.imooc.jdbc.utils;

import java.sql.*;

public class JDBCUtils {

private static final String driverClass;

private static final String ip;

private static final String port;

private static final String database;

private static final String user;

private static final String password;

private static final String character;

private static final String url;

static { //静态加载

driverClass = "com.mysql.cj.jdbc.Driver";

ip = "148.70.251.10";

port = "3306";

database = "jdbctest";

user = "root";

password = "123456";

character = "useUnicode=yes&characterEncoding=utf8";

url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?" + character;

}

  //加载驱动器

public static void loadDriver() throws ClassNotFoundException {

Class.forName(driverClass);

}

  //获取连接

public static Connection getConnection() throws Exception{

loadDriver();

Connection conn = DriverManager.getConnection(url, user, password);

return conn;

}

  //释放连接

public static void release(Statement stmt,Connection conn){

if (stmt != null) {

try {

stmt.close();

} catch (Exception e) {

e.printStackTrace();

}

stmt = null;

}

if (conn != null) {

try {

conn.close();

} catch (Exception e) {

e.printStackTrace();

}

conn = null;

}

}

public static void release(ResultSet rs,Statement stmt,Connection conn){

if (rs != null) {

try {

rs.close();

} catch (Exception e) {

e.printStackTrace();

}

rs = null;

}

release(stmt,conn);

}

}

(2)简单使用

package com.imooc.jdbc.test;

import com.imooc.jdbc.utils.JDBCUtils;

import org.omg.Messaging.SYNC_WITH_TRANSPORT;

import java.sql.ResultSet;

import java.sql.Statement;

import java.sql.Connection;

public class test {

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try{

conn = JDBCUtils.getConnection(); //获取连接

stmt = conn.createStatement();

String sql = "select * from user";

rs = stmt.executeQuery(sql);

while (rs.next()){

int uid = rs.getInt("uid");

String name = rs.getString("name");

String mobile = rs.getString("mobile");

String addr = rs.getString("addr");

System.out.println(uid+" "+name+" "+mobile+" "+addr);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

JDBCUtils.release(rs,stmt,conn); //一次释放

}

}

}

(3)配置文件优化

如果我们想在一个配置文件中配置参数,可以将其剥离出来。
创建jdbc.properties,然后使用类加载器加载配置:

static {

//加载属性文件并解析

Properties props = new Properties();

//通过类加载器获取

InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");

try {

props.load(is);

} catch (IOException e) {

e.printStackTrace();

}

driverClass = props.getProperty("driverClass");

ip = props.getProperty("ip");

port = props.getProperty("prot");

database = props.getProperty("database");

user = props.getProperty("user");

password = props.getProperty("password");

character = props.getProperty("character");

url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?" + character;

}

4.SQL注入

SQL注入的实质是修改了SQL语句。输入了SQL语句的关键字,从而修改了逻辑。
select * from user where username = “xxx” and password = “xxx”;

如果我们在输入username的时候进行注入,比如:
username = “xxx ‘or ‘1=1”

结果就变成这样了:
select * from user where username = “xxx ‘or ‘1=1” and password = “xxx”;

无形之间,就修改SQL语句的逻辑。

js校验能够拦截一些初级注入,但是可以修改url来突破。
上述问题还是在于,SQL语句采用的字符串拼接方式。
在python中采用字符串拼接或者%替换都无法解决SQL注入的问题,一般解决方法有二:
  a.对传入的参数进行编码转义
  b.使用python的MySQLdb模块的execute方法。
    cursor.execute(query, params)
    第一个是参数化的sql语句,第二个是对应的实际的参数值。
    函数内部escape_string方法会对传入的参数值进行相应的处理(主要是转化为字符串)防止sql注入。

在Java中解决SQL注入漏洞可以使用PreparedStatement。
PreparedStatement是Statement的子接口,
它的实例对象可以通过调用Connection.preparedStatement(sql)方法获得,
相对于Statement对象而言:
  PreperedStatement可以避免SQL注入的问题。
  Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
  PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。
  并且PreparedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化SQL语句的编写。
String sql = "select * from user";
stmt = conn.createStatement(); //将其类型改为PreparedStatement即可
//执行sql语句
resultSet = stmt.executeQuery(sql);

采用预编译的方式,会将SQL语句的结构固定,你再传入关键字也不会改变SQL语句的结构。
String sql = “select * from user where username = ? and password = ?”
pstmt = conn.prepareStatement(sql)
pstmt.setString(1,username)
pstmt.setString(2,password)
pstmt.executeQuery()

以上是 Java之JDBC 的全部内容, 来源链接: utcz.com/z/393620.html

回到顶部