第二章 jdbc深入编程 ① 笔记
内容回顾
jdbc API的常用接口有哪些
如何插入数据到数据库
如何从数据库查询数据
本章内容
1、PreaparedStatement使用
2、实现录入并得到自增列的值
3、实现事务操作
4、封装完整的BaseDao
第一节 预编译命令对象
1.1 PreparedStatement
继承自 statement接口
预编译的sql语句对象;
对sql语句进行预编译,存储到PreparedStatement对象中,可以多次执行命令,提
高效率。
杜绝sql注入式攻击,安全性高。使用的是参数式的sql命令。
insert into table1 (id,name,sex) values(?,?,?);
使用PrepareStatement实现数据库操作
通过连接对象获取PreparedStatement对象
String sql =
"select * from student where name=? or sex = ? or phone=?"
PreparedStatement pst = 连接对象.prepareStatement(sql);
pst.setObject(1,"张三");
pst.setObject(2,"男");
pst.setObject(3,"131123123");
pset.setObject(4,"xx"); #没有第四个参数,不能写,报错
//BaseDAO:base database access object : 基本数据访问对象
public class BaseDAO {
//定义数据库连接属性(四大金刚)
private static String driver = "com.mysql.cj.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/0516_db?useSSL=
private static String user="root";
private static String password="123456";
//获取连接
public static Connection getConnection(){
Connection con = null;
try{
//加载驱动类
Class.forName(driver);
//使用DriverManager获取连接对象
con = DriverManager.getConnection(url,user,password);
}catch (Exception ex){
ex.printStackTrace();
}
return con;
}
//关闭数据库对象
public static void closeAll(Connection con, 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(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//通用设置参数
public static void setParams(PreparedStatement pst,Object[] params){
//如果没有参数,则直接返回
if(params==null)
return;
//循环设置参数
for (int i=0;i<params.length;i++){
try {
pst.setObject(i+1,params[i]);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
第二节 获取自增列的值
插入记录之后,将记录的自增值获取到。
关键代码:
//创建预编译命令对象时,要提供获取自增值的参数
pst = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
...
//获取自增返回的结果集对象
rs = pst.getGeneratedKeys();
int id=0;
if(rs.next()){
id=rs.getInt(1);
}
完整示例:
package com.test2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test3 extends BaseDAO{
public void insert(){
Connection con = null;
PreparedStatement pst = null;
ResultSet rs=null;
String sql="insert into test"
+ " (tname,tdate)"
+ " values"
+ " (?,?)";
try {
con = getConnection();
pst = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
pst.setString(1, "wangwu");
pst.setString(2, "2010-01-01");
int res = pst.executeUpdate();
System.out.println("插入的记录数:"+res);
//获取自增返回的结果集对象
rs = pst.getGeneratedKeys();
int id=0;
if(rs.next()){
id=rs.getInt(1);
}
System.out.println("记录的id是:"+id);
} catch (Exception e) {
e.printStackTrace();
} finally{
closeAll(con,pst,rs);
}
}
public static void main(String[] args) {
Test3 t=new Test3();
t.insert();
}
}
实现:录入学生信息,以及学生的成绩信息,学生和成绩分两表存储
第三节 事务
什么是事务?
一种机制:确保一系列的数据操作作为原子(整体)去执行,要么都执行,要么都不执
行(回滚);
数据库表:
create table bank
(
bid int auto_increment primary key,
accountName varchar(20),
money float(5,1)
)
insert into bank
(accountName,money)
select '张三',9999.9 union
select '李四',9999.9
java中如何处理事务?
事务的四个特性:ACID是**原子性(atomicity)、一致性(consistency)、隔离性
(isolation)和持久性(durability)**的缩写。
事务的原子性:事务作为整体执行,要么都成功,要么都回滚。
事务的一致性:表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执
行前的状态。
事务的隔离性:多个事务在并发执行过程中,是相互独立的(隔离的)比如:售票过
程。
事务的持久性:事务对数据库所做的操作是永久性的。
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口(
java.sql.Connection )提供了两种事务模式:自动提交和手工提交。
java.sql.Connection 提供了以下控制事务的方法:
public void setAutoCommit(boolean) 设置事务的提交方式
public boolean getAutoCommit() --获取自动提交的状态
public void commit() --提交事务
public void rollback() --回滚事务
关键代码:
con = getConnection();
//设置手动事务
con.setAutoCommit(false);
//提交事务
con.commit();
//回滚事务
con.rollback();
完整示例:
基于事务实现,必须使用同一个Connection对象;
package com.test2;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test2 extends BaseDAO{
public void insert(){
/*
create table bank
(
bid int auto_increment primary key,
accountName varchar(20),
money float(5,1)
)
insert into bank
(accountName,money)
select '张三',9999.9 union
select '李四',9999.9
select * from bank;
*/
Connection con = null;
PreparedStatement pst = null;
ResultSet rs = null;
String sql1="update bank "
+ " set money=money-1000 "
+ " where accountName='张三'";
String sql2="update bank "
+ " set money=money+1000 "
+ " where accountName='李四'";
try {
con = getConnection();
con.setAutoCommit(false);
pst = con.prepareStatement(sql1);
int res = pst.executeUpdate();
System.out.println("更新的记录数:"+res);
pst = con.prepareStatement(sql2);
res = pst.executeUpdate();
System.out.println("更新的记录数:"+res);
//提交事务
con.commit();
System.out.println("事务提交成功");
} catch (Exception e) {
e.printStackTrace();
try {
con.rollback();
System.out.println("回滚事务");
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} finally{
closeAll(con,pst,rs);
}
}
public static void main(String[] args) {
Test2 t=new Test2();
t.insert();
}
}
第四节 封装BaseDAO
为了减少冗余代码
BaseDAO:
package com.yzh6.util;
import java.sql.*;
import java.util.*;
public class BaseDAO{
//数据库属性
private static String driver = "com.mysql.cj.jdbc.Driver";
private static String url="jdbc:mysql://localhost:3306/0516_db?useSSL=fal
private static String user="root";
private static String password ="123456";
//获取连接
public static Connection getConnection(){
Connection con = null;
try{
Class.forName(driver);
con= DriverManager.getConnection(url,user,password);
}catch(Exception ex){
ex.printStackTrace();
}
return con;
}
//关闭数据库对象
public static void closeAll(Connection con,Statement st,ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
if(st!=null){
try{
st.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
if(con!=null){
try{
con.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
//设置参数
public static void setParams(PreparedStatement pst,Object[] params){
if(params==null)
return;
for(int i=0;i<params.length;i++){
try{
pst.setObject(i+1,params[i]);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
//通用增删改
public static int executeUpdate(String sql,Object[] params){
int res = -1;
Connection con = null;
PreparedStatement pst =null;
try{
con = getConnection();
pst = con.prepareStatement(sql);
setParams(pst,params);
res = pst.executeUpdate();
}catch(Exception ex){
ex.printStackTrace();
}finally{
closeAll(con,pst,null);
}
return res;
}
//通用查询
public static List<Map> executeQuery(String sql,Object[] params){
List<Map> rows = new ArrayList<Map>();
Connection con = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
con = getConnection();
pst = con.prepareStatement(sql);
setParams(pst,params);
rs = pst.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
while(rs.next()){
Map map = new HashMap();
for(int i=1;i<=colCount;i++){
String colName = rsmd.getColumnName(i);
Object colVal = rs.getObject(i);
map.put(colName,colVal);
}
rows.add(map);
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
closeAll(con,pst,rs);
}
return rows;
}
}
总结
1、
PreparedStatement对象代表的是一个预编译的SQL语句。用它提供的setter方法可以
传入查询的变量。
由于PreparedStatement是预编译的,通过它可以将对应的SQL语句高效的执行多次。
由于PreparedStatement自动对特殊字符转义,避免了SQL注入攻击,因此应当尽量的
使用它。
2、
可以使用它的setNull方法来把null值绑定到指定的变量上。setNull方法需要传入参数的
索引以及SQL字段的类型,像这样:
ps.setNull(10, java.sql.Types.INTEGER);
3、
有的时候表会生成主键,这时候就可以用Statement的getGeneratedKeys()方法来获取
这个自动生成的主键的值了。
4、
它和Statement相比优点在于:
PreparedStatement有助于防止SQL注入,因为它会自动对特殊字符转义。
PreparedStatement可以用来进行动态查询。
PreparedStatement执行更快。尤其当你重用它或者使用它的拼量查询接口执行多
条语句时。
使用PreparedStatement的setter方法更容易写出面向对象的代码,而Statement的
话,我们得拼接字符串来生成查询语句。如果参数太多了,字符串拼接看起来会非
常丑陋并且容易出错。
练习任务
1、熟练掌握本章节的各知识点
2、熟练封装BaseDao并使用。
// A code block
var foo = 'bar';
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118096.html