JDBC详解
1.数据库驱动
程序不直接与数据库进行交互,而是通过数据库驱动和数据库打交道。
2.JDBC
没有什么事是加一层解决不了的。
SUN公司为了简化开发人员的(对数据库统一)操作,提供了一个(Java操作数据库的)规范,俗称JDBC,这些规范的实现由具体的厂商去做。
对于开发人员来说,只需要掌握JDBC的接口即可。
3.第一个JDBC程序
-
首先创建一个普通的java程序。
-
创建lib目录,导入数据库驱动。
-
右键 add
-
编写测试代码
package com.li.demo01;
?
import java.sql.*;
?
// 我的第一个jdbc程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
// 2.用户信息和url
String url = "jdbc:mysql://localhost:3306/ks?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";
String password = "123456";
// 3.连接成功,获得数据库连接对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 4.执行sql语句的对象 Statement 执行sql的对象
Statement statement = connection.createStatement();
// 5.执行sql语句的对象去执行sql,获得结果集
String sql = "SELECT * FROM info";
ResultSet resultSet = statement.executeQuery(sql);
// 6.得到返回的结果集,取出展示
while (resultSet.next()){
System.out.println("info_id=" + resultSet.getObject("info_id"));
System.out.println("info_title=" + resultSet.getObject("info_title"));
System.out.println("info_content=" + resultSet.getObject("info_content"));
System.out.println("root_id=" + resultSet.getObject("root_id"));
System.out.println("info_date=" + resultSet.getObject("info_date"));
System.out.println("===========================================");
}
// 7.释放连接
resultSet.close();
statement.close();;
connection.close();
}
}
步骤总结:
-
加载驱动。
-
填写数据库连接需要的相应信息。
-
连接数据库,获得数据库连接对象。
-
获取执行sql语句的对象。
-
执行sql得到结果集。
-
遍历结果集,打印出来。
-
释放连接。
4.JDBC中对象的解释
数据库驱动:
Class.forName("com.mysql.jdbc.Driver"); --这是固定加载mysql驱动的写法
执行Driver里面的静态代码块,new一个Driver驱动。
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
?
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
?
用DriverManager来连接数据库,得到数据库连接对象。
Connection connection = DriverManager.getConnection(url, username, password);
connection 代表数据库,即可以操作数据库事务
connection.commit();
connection.setAutocommit();
connection.rollback();
url:
Srting url = "jdbc:mysql://localhost:3306/ks?useUnicode=true&charecterEncoding=utf8&useSSL=true"; ? -- jdbc:mysql 这是协议 就像 http:www: -- localhost 这是地址 -- ks 数据库名称 -- useUnicode=true&charecterEncoding=utf8&useSSL=true 参数 使用中文、字符编码、安全协议 ? 即: String url = " 协议 : 主机地址:端口号/数据库名称?相关参数"
Statement 执行sql的对象:
用于向数据库发送sql语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
statement.executeQuery(); --查询操作,返回resultSet statement.execute(); --执行任何的sql statement.executeUpdate(); --更新、插入、删除、都是用这个,这个不返回resultSet,返回一个受影响的行数
resultSet查询的结果集:封装了所有的查询结果
resultSet.getObject(); --在不知道列类型的情况下使用 ? 如果知道列类型的就使用固定的类型 resultSet.getString(); resultSet.getInt(); resultSet.getFloat(); resultSet.getDate(); resultSet.get...(); ? 遍历,指针 resultSet.next(); --移动到下一个数据 resultSet.beforeFirst(); --移动到最前面 resultSet.afterLast(); --移动到最后面
5.提取工具类
db.properties:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/ks?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456
JdbcUtils:
package com.li.demo02.utils; ? import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; ? public class JdbcUtils { private static String driver = null; private static String url = null; private static String username = null; private static String password = null; ? static { try{ InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.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(); } } ? //获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } ? //释放资源 public static void release(Connection conn, Statement st, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(st!=null){ try { st.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } }
TestUtils:
-- 插入数据
package com.li.demo02;
?
import com.li.demo02.utils.JdbcUtils;
?
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
?
public class TestUtils {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql ="INSERT INTO info(`info_id`,`info_title`,`info_content`,`root_id`,`info_date`) VALUES (7,'某某公司招聘公告','这是某某公司的招聘公告',1,'2020-12-17 14:57:52')";
int i = st.executeUpdate(sql);
if(i > 0){
System.out.println("数据插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
?
-- 修改数据
package com.li.demo02;
?
import com.li.demo02.utils.JdbcUtils;
?
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
?
public class TestUtilsUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "UPDATE info SET info_content = '这是某某公司修改过的招聘公告-----' WHERE info_id = 7";
int i = st.executeUpdate(sql);
if(i > 0){
System.out.println("信息修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
?
-- 查询数据
package com.li.demo02;
?
import com.li.demo02.utils.JdbcUtils;
?
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
?
public class TestUtilsSelect {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "select * from info";
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println("info_id=" + rs.getObject("info_id"));
System.out.println("info_title=" + rs.getObject("info_title"));
System.out.println("info_content=" + rs.getObject("info_content"));
System.out.println("root_id=" + rs.getObject("root_id"));
System.out.println("info_date=" + rs.getObject("info_date"));
System.out.println("===========================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
?
}
}
?
-- 删除数据
package com.li.demo02;
?
import com.li.demo02.utils.JdbcUtils;
?
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
?
public class TestUtilsDelete {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "delete from info where info_id = 7";
int i = st.executeUpdate(sql);
if(i > 0){
System.out.println("信息删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
6.SQL注入问题
sql存在安全漏洞,会被攻击导致数据歇漏。本质:sql会被拼接。
例如在用户登录的时候,传入相应的参数,恶意拼接sql,修改查询匹配的条件。
login(username:" 'or '1=1",password:" 'or '1=1");
7.PreparedStatement对象
可以防止sql注入。效率更好。
与Statement的区别在于:sql语句里面不是写完整的数据库查询语句,而是在里面使用 ? 占位符,然后先预编译sql,后面再来给他设置值,最后执行sql。
-- 插入数据
package com.li.demo03;
import com.li.demo02.utils.JdbcUtils;
import java.util.Date;
import java.sql.*;
?
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils.getConnection();
// 区别
//使用 ? 占位符代替参数
String sql = "INSERT INTO info(`info_id`,`info_title`,`info_content`,`root_id`,`info_date`) VALUES (?,?,?,?,?)";
st = conn.prepareStatement(sql); //预编译sql,然后不执行
//预编译之后手动给参数赋值
st.setInt(1,7);
st.setString(2,"这是新的工厂");
st.setString(3,"这是新的工厂招聘信息");
st.setInt(4,1);
// 注意点,这两个date是不一样的
st.setDate(5,new java.sql.Date(new Date().getTime()));
//最后执行
int i = st.executeUpdate();
if(i > 0){
System.out.println("信息插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
?
-- 修改数据
package com.li.demo03;
import com.li.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
?
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql ="update info set info_content = ? where info_id = ?";
st = conn.prepareStatement(sql);
st.setString(1,"这是修改过后的信息-----------");
st.setInt(2,7);
int i = st.executeUpdate();
if (i > 0){
System.out.println("信息修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
?
-- 查询数据
package com.li.demo03;
import com.li.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
?
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from info where info_id = ?";
st = conn.prepareStatement(sql);
st.setInt(1,7);
rs = st.executeQuery();
while (rs.next()){
System.out.println("info_id=" + rs.getObject("info_id"));
System.out.println("info_title=" + rs.getObject("info_title"));
System.out.println("info_content=" + rs.getObject("info_content"));
System.out.println("root_id=" + rs.getObject("root_id"));
System.out.println("info_date=" + rs.getObject("info_date"));
System.out.println("===========================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
?
-- 删除数据
package com.li.demo03;
import com.li.demo02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
?
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "delete from info where info_id = ?";
st = conn.prepareStatement(sql);
st.setInt(1,7);
int i = st.executeUpdate();
if (i > 0){
System.out.println("信息删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
8.代码实现JDBC事务
-
关闭自动提交事务,自动开启事务。
-
conn.setAutoCommit(false);
-
-
执行完sql之后,注意需要手动提交事务。
-
conn.commit();
-
-
失败则回滚。
-
conn.rollback();
-
具体代码实现:
package com.li.demo03;
import com.li.demo02.utils.JdbcUtils;
import java.util.Date;
import java.sql.*;
?
public class TestInsert {
public static void main(String[] args) throws SQLException {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//开启事务,关闭数据库的自动提交,自动会开启事务
conn.setAutoCommit(false);
String sql1 = "INSERT INTO info(`info_id`,`info_title`,`info_content`,`root_id`,`info_date`) VALUES (?,?,?,?,?)";
st = conn.prepareStatement(sql1);
st.setInt(1,7);
st.setString(2,"这是新的工厂");
st.setString(3,"这是新的工厂招聘信息");
st.setInt(4,1);
st.setDate(5,new java.sql.Date(new Date().getTime()));
//最后执行
int i = st.executeUpdate();
String sql2 = "update info set info_content = ? where info_id = ?";
st = conn.prepareStatement(sql2);
st.setString(1,"1111111111111111111");
st.setInt(2,7);
st.executeUpdate();
//业务完毕,提交事务
conn.commit();
System.out.println("事务执行完毕!");
} catch (SQLException e) {
conn.rollback(); //如果失败就回滚
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
9.数据库连接池
数据库连接------执行sql------释放连接。
这个过程十分浪费资源。
池化技术:准备一些预先的资源,进来就直接用预先准备好的。
最小连接数
最大连接数
等待超时
开源数据源实现:
DBCP
需要使用的jar包。
commons-dbcp-1.4 commons-pool-1.6
dbcpconfig.properties:
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/ks?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456
-- 注意:这里的driverClassName 是固定的写法
数据源里面封装的方法,固定用的就是这个名字,不然找不到
还有就是后面不能带有注释,否则会包加载不了驱动的错误
JdbcUtils_DBCP:
package com.li.demo04.utils; import com.li.demo02.utils.JdbcUtils; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.*; import java.util.Properties; ? public class JdbcUtils_DBCP { ? private static DataSource dataSource = null; static { try{ InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); Properties properties = new Properties(); properties.load(in); //创建数据源 dataSource = BasicDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } ? //获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); //从数据源中获取相应的信息 } ? //释放资源 public static void release(Connection conn, Statement st, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(st!=null){ try { st.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } ? ? -- 与前面不一样的就是,使用了封装的数据源datasource. 使用工厂模式创建 dataSource = BasicDataSourceFactory.createDataSource(properties); 获取连接也是使用封装好的方法: dataSource.getConnection();
TestDBCP:
package com.li.demo04;
import com.li.demo04.utils.JdbcUtils_DBCP;
import java.sql.*;
public class TestDBCP {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils_DBCP.getConnection();
String sql = "select * from info where info_id = ?";
st = conn.prepareStatement(sql);
st.setInt(1, 7);
rs = st.executeQuery();
while (rs.next()) {
System.out.println("info_id=" + rs.getObject("info_id"));
System.out.println("info_title=" + rs.getObject("info_title"));
System.out.println("info_content=" + rs.getObject("info_content"));
System.out.println("root_id=" + rs.getObject("root_id"));
System.out.println("info_date=" + rs.getObject("info_date"));
System.out.println("===========================================");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils_DBCP.release(conn, st, rs);
}
}
}?
C3P0
需要使用到的jar包:
c3p0-0.9.5.5 mchange-commons-java-0.2.19
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> ?<default-config> "driverClass">com.mysql.jdbc.Driver "jdbcUrl">jdbc:mysql://localhost:3306/ks?useUnicode=true&characterEncoding=utf8&useSSL=true "user">root "password">123456 ?"initialPoolSize">10 "maxIdleTime">30 "maxPoolSize">100 "minPoolSize">10 default-config> ?"mySource"> "driverClass">com.mysql.jdbc.Driver "jdbcUrl">jdbc:mysql://localhost:3306/bookstore "user">root "password">xxxx ?"initialPoolSize">10 "maxIdleTime">30 "maxPoolSize">100 "minPoolSize">10
JdbcUtils_C3P0:
package com.li.demo04.utils; ? import com.li.demo02.utils.JdbcUtils; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; ? public class JdbcUtils_C3P0 { private static DataSource dataSource = null; static { try{ //配置文件写法,里面没有参数则是默认的,加了就匹配对应的 dataSource = new ComboPooledDataSource(); } catch (Exception e) { e.printStackTrace(); } } ? //获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); //从数据源中获取相应的信息 } ? //释放资源 public static void release(Connection conn, Statement st, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(st!=null){ try { st.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } } ? -- 一行代码解决所有连接问题 dataSource = new ComboPooledDataSource();
TestC3P0:
package com.li.demo04;
?
import com.li.demo04.utils.JdbcUtils_C3P0;
?
?
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
?
public class TestC3P0 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
?
try {
conn = JdbcUtils_C3P0.getConnection();
String sql = "select * from info where info_id = ?";
st = conn.prepareStatement(sql);
st.setInt(1, 7);
rs = st.executeQuery();
while (rs.next()) {
System.out.println("info_id=" + rs.getObject("info_id"));
System.out.println("info_title=" + rs.getObject("info_title"));
System.out.println("info_content=" + rs.getObject("info_content"));
System.out.println("root_id=" + rs.getObject("root_id"));
System.out.println("info_date=" + rs.getObject("info_date"));
System.out.println("===========================================");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils_C3P0.release(conn, st, rs);
}
}
}
总结: