由于在项目中使用Hibernate居多,从而JDBC直接使用慢慢减少,突然看了下视频整理对之前知识的查漏补缺。
连接数据的步骤
注册驱动
- Class.forName(“com.mysql.jdbc.Driver”);
推荐这种方式,不会对具体的驱动类产生依赖。
- DriverManager.registerDriver(com.mysql.jdbc.Driver);
会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
- System.setProperty(“jdbc.drivers”, “driver1:driver2”);
虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。
建立连接
-
Connectionconn = DriverManager.getConnection ( url , user, password);
-
url 格式: JDBC: 子协议 : 子名称 // 主机名 : 端口 / 数据库名?属性名 = 属性值 &…
-
User,password 可以用“属性名 = 属性值”方式告诉数据库;其他参数如:useUnicode=true&characterEncoding=GBK
创建执行SQL的语句(Statement)
- Statement
Statement st = conn.createStatement();
st.executeQuery(sql);
- PreparedStatement
Stringsql= “select * from table_name where col_name=?”;
PreparedStatementps = conn.preparedStatement(sql);
ps.setString(1, “col_value”);
ps.executeQuery();
处理执行结果(ResultSet)
ResultSetrs= statement.executeQuery(sql);
While(rs.next()){
rs.getString(“col_name”);
rs.getInt(“col_name”);
//…
}
释放资源
- 释放ResultSet,Statement,Connection.
- 数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放
整合起来的可参考规范(使用单例模式)
将注册、建立连接和释放资源整合到一个JdbcUtils类中
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public final class JdbcUtilsSing {
private String url = "jdbc:mysql://localhost:3306/jdbc";
private String user = "root";
private String password = "";
// private static JdbcUtilsSing instance = new JdbcUtilsSing();
private static JdbcUtilsSing instance = null;
private JdbcUtilsSing() {
}
/**利用延迟加载并且加锁解决并发问题:使用的时候才new实例
* @return
*/
public static JdbcUtilsSing getInstance() {
//双重检查来避免instance为null的问题
if (instance == null) {
synchronized (JdbcUtilsSing.class) {
if (instance == null) {
instance = new JdbcUtilsSing();
}
}
}
return instance;
}
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
public void free(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
模板使用的例子:
static void template() throws Exception {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();
// 4.执行语句
rs = st.executeQuery("select * from user");
// 5.处理结果
while (rs.next()) {
// 参数中的1,2,3,4是指sql中的列索引
System.out.println(rs.getObject(1) + "\t" + rs.getObject(2)
+ "\t" + rs.getObject(3) + "\t" + rs.getObject(4));
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}
CRUD的操作
连接数据库的步骤跟以上是一样的
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class CRUD {
/**
* @param args
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
create();
read();
update();
delete();
}
/**
* 删除
* @throws SQLException
*/
static void delete() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();
String sql = "delete from user where id>4";
// 4.执行语句
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
/**
* 更新
* @throws SQLException
*/
static void update() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();
String sql = "update user set money=money+10 ";
// 4.执行语句
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
/**
* 创建
* @throws SQLException
*/
static void create() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();
String sql = "insert into user(name,birthday, money) values ('name1', '1987-01-01', 400) ";
// 4.执行语句
int i = st.executeUpdate(sql);
System.out.println("i=" + i);
} finally {
JdbcUtils.free(rs, st, conn);
}
}
/**
* 查询
* @throws SQLException
*/
static void read() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
st = conn.createStatement();
// 4.执行语句
rs = st.executeQuery("select id, name, money, birthday from user");
// 5.处理结果
while (rs.next()) {
System.out.println(rs.getObject("id") + "\t"
+ rs.getObject("name") + "\t"
+ rs.getObject("birthday") + "\t"
+ rs.getObject("money"));
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}
}
CRUD的小结:
- 增、删、改用Statement.executeUpdate来完成,返回整数(匹配的记录数),这类操作相对简单。
- 查询用Statement.executeQuery来完成,返回的是ResultSet对象,ResultSet中包含了查询的结果;查询相对与增、删、改要复杂一些,因为有查询结果要处理。
处于SQL注入问题的改善:PreparedStatement
- 在SQL中包含特殊字符或SQL的关键字(如:' or 1 or ')时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
- PreperedStatement(从Statement扩展而来)相对Statement的优点:
1.没有SQL注入的问题。
2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
3.数据库和驱动可以对PreperedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。
PreparedStatement使用的例子
static void read(String name) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 2.建立连接
conn = JdbcUtils.getConnection();
// conn = JdbcUtilsSing.getInstance().getConnection();
// 3.创建语句
String sql = "select id, name, money, birthday from user where name=?";
ps = conn.prepareStatement(sql);
ps.setString(1, name);
// 4.执行语句
rs = ps.executeQuery();
// 5.处理结果
while (rs.next()) {
System.out.println(rs.getInt("id") + "\t"
+ rs.getString("name") + "\t" + rs.getDate("birthday")
+ "\t" + rs.getFloat("money"));
}
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
代码“rs = ps.executeQuery();” executeQuery()方法同样可以添加参数不会编译异常,由于PreparedStatement是继承Statement,从而添加参数只是调用Statement的executeQuery(sql)方法。因为Statement是通过拼字符串形式交给数据库执行SQL语句,从而无法识别“?”就会报异常。