Java之JDBC
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