文章目录
JDBC概述
理解:web应用 html语法 ---- java语法 ----- sql语法
任何持久层数据库连接的框架都是以jdbc为基础。(mybatis、hibernate、data-jpa、自定义持久层框架)
JDBC是Java Database Connectivity的缩写,意为Java数据库连接。是Java提供的一种数据库访问规则、规范, 由于数据库种类较多,并且java语言使用比较广泛,sun公司就提供了一种规范,让其他的数据库提供商去实现底层的访问规则。 Java程序只要使用sun公司提供的标准接口去操作数据库即可。
JDBC主要API
- DriverManager (管理驱动:注册驱动、获取连接对象)
- Connection (代表到数据库的连接,获取执行对象)
- Statement、PreparedStatement (执行对象,可以执行CRUD语句)
- ResultSet (查询结果集对象,封装了查询结果)
JDBC CRUD操作
JDBC操作数据库一般流程
我们在使用JDBC操作数据库时的流程是固定的:
- 加载驱动类(只需加载一次,新版本JDK可以省略)
- 建立连接
Connection
- 获取执行语句对象
Statement
或PreparedStatement
- 执行sql
- 封装结果集
- 释放资源、关闭连接
查询示例:
package com.lanou.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Jdbc01 {
/*
* 通过jdbc连接mysql,查询学生表所有数据,在控制台打印输出
*/
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//jdbc操作基本步骤
//1、加载驱动类
Class.forName("com.mysql.jdbc.Driver");
//2、建立连接 建立和mysql的连接
//jdbc:mysql://ip地址或主机名:端口号/库名?useSSL=false
String url = "jdbc:mysql://localhost:3306/studentmanage?useSSL=false";
Connection conn = DriverManager.getConnection(url,
"root", "123456");
//3、创建一个Statement语句
Statement stmt = conn.createStatement();
//4、执行sql 获取结果集
String sql = "select * from student";
ResultSet rs = stmt.executeQuery(sql);
//5、封装结果集(输出数据)
while(rs.next()) {
//获取当前行数据
int sid = rs.getInt("sid");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
int sage = rs.getInt("sage");
System.out.println("学号:"+sid+ " 姓名:"+sname+" 性别:"+ssex+" 年龄:"+sage);
}
//6、关闭资源、释放连接 先开的后关
rs.close();
stmt.close();
conn.close();
}
}
增删改:
package com.lanou.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Jdbc02 {
/**
* 新增学生
* 修改学生信息 将鑫鑫的年龄加减2岁
* 删除学生 通过主键id列删除数据
* @param args
* @throws ClassNotFoundException
* @throws SQLException
*/
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2、建立连接
String url = "jdbc:mysql://localhost:3306/studentmanage?useSSL=false";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
//3、获取Statement语句
Statement stmt = conn.createStatement();
//4、执行sql
String sql = "insert into student(sname,sage,ssex) values ('鑫鑫',20,'男')";
//执行任何sql,但是返回的是受影响的数据行数
int num = stmt.executeUpdate(sql);
//5、处理结果集
System.out.println("新增成功:"+num);
//6、关闭结果集
stmt.close();
conn.close();
}
}
封装jdbcUtil工具类
package com.lanou.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/*
* 打开连接
* 关闭连接
*/
public class JdbcUtil {
private static final String url = "jdbc:mysql://localhost:3306/studentmanage?useSSL=false";
private static final String username = "root";
private static final String password = "123456";
private static Connection conn = null;
static {
//1、加载驱动类
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection open() {
try {
conn = DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(ResultSet rs,Statement stmt,Connection conn) {
//6、关闭资源、释放连接 先开的后关
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
使用jdbcUtil工具类完成查询
public void query(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtil.open();
//3、创建一个Statement语句
stmt = conn.createStatement();
//4、执行sql 获取结果集
String sql = "select * from student";
rs = stmt.executeQuery(sql);
//5、封装结果集(输出数据)
while(rs.next()) {
//获取当前行数据
int sid = rs.getInt("sid");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
int sage = rs.getInt("sage");
System.out.println("学号:"+sid+ " 姓名:"+sname+" 性别:"+ssex+" 年龄:"+sage);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
}
注入攻击问题?
//根据姓名查询
public void query(String name){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtil.open();
//3、创建一个Statement语句
stmt = conn.createStatement();
//4、执行sql 获取结果集
String sql = "select * from student where sname='"+name+"' ";
rs = stmt.executeQuery(sql);
//5、封装结果集(输出数据)
while(rs.next()) {
//获取当前行数据
int sid = rs.getInt("sid");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
int sage = rs.getInt("sage");
System.out.println("学号:"+sid+ " 姓名:"+sname+" 性别:"+ssex+" 年龄:"+sage);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
}
public static void main(String[] args){
//sql注入攻击
new Jdbc04().query("鑫鑫' or '1' = '1 ");
}
总结:
Statement语句弊端:
1、拼接sql非常麻烦导致开发效率低
2、可能存在注入攻击问题,倒是数据不安全
如何解决?
PreparedStatment 代替 Statement
PreparedStatment
优点:无需拼接sql,开发效率高
预编译过程,执行效率高
可以避免注入攻击,安全性能更好
Statement与PreparedStatement的区别
Statement接口用来执行一段SQL语句并返回结果,不支持参数占位符写法。Statement执行 ,其实是拼接sql语句的。 先拼接sql语句,然后在一起执行。如果传入的参数是一段可执行的SQL,也会被执行,有SQL注入的风险。
PreparedStatement接口继承自Statement接口,相比较以前的statement, 预先处理给定的sql语句,对其执行语法检查。 在sql语句里面使用 ? 占位符来替代后续要传递进来的变量。 后面进来的变量值,只会被看成参数值,不会产生任何的关键字的效果。
实践操作:
能够使用PreparedStament完成常见的增上改查:
package com.lanou.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.lanou.bean.Student;
import com.lanou.util.JdbcUtil;
/*
* 学生常见操作
* 面试:
* 1、jdbc操作基本流程
* 2、Statement和PreparedStatement的区别和练习
* 3、常见增删改查
*/
public class StudentDao {
//新增一个学生对象
public int save(Student student) {
Connection conn = null;
PreparedStatement stmt = null;
int num = 0;
try {
conn = JdbcUtil.open();
//? 问号占位符
String sql = "insert into student(sname,ssex,sage) values (?,?,?)";
//预编译sql
stmt = conn.prepareStatement(sql);
//给 ?号占位符赋值
stmt.setString(1, student.getSname());
stmt.setString(2, student.getSsex());
stmt.setInt(3, student.getSage());
//执行sql
num = stmt.executeUpdate();
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(null, stmt, conn);
}
return num;
}
//查询所有学生对象
public List<Student> findAll(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<Student> list = new ArrayList<>();
try {
conn = JdbcUtil.open();
String sql = "select * from student";
stmt = conn.prepareStatement(sql);
//执行查询
rs = stmt.executeQuery();
//遍历
while(rs.next()) {
int sid = rs.getInt("sid");
int sage = rs.getInt("sage");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
//每循环一次,创建一个对象
Student s = new Student(sid,sname,ssex,sage);
list.add(s);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return list;
}
//通过主键查询一个学生对象
public Student findOne(int sid){
Connection conn = null;
PreparedStatement stmt = null;
Student student = null;
ResultSet rs = null;
try {
conn = JdbcUtil.open();
String sql = "select * from student where sid = ?";
stmt = conn.prepareStatement(sql);
//赋值
stmt.setInt(1, sid);
//执行查询
rs = stmt.executeQuery();
//遍历
if(rs.next()) {
//每循环一次,创建一个对象
int sid1 = rs.getInt("sid");
int sage = rs.getInt("sage");
String sname = rs.getString("sname");
String ssex = rs.getString("ssex");
student = new Student(sid1,sname,ssex,sage);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(null, stmt, conn);
}
return student;
}
//修改学生对象
public int update(Student student) {
Connection conn = null;
PreparedStatement stmt = null;
int num = 0;
try {
conn = JdbcUtil.open();
String sql = "update student set sname=? , ssex=? ,sage=? where sid = ?";
stmt = conn.prepareStatement(sql);
//赋值
stmt.setString(1, student.getSname());
stmt.setString(2, student.getSsex());
stmt.setInt(3, student.getSage());
stmt.setInt(4, student.getSid());
//执行sql
num = stmt.executeUpdate();
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(null, stmt, conn);
}
return num;
}
//删除学生对象 通过主键删除
public int delete(int sid) {
Connection conn = null;
PreparedStatement stmt = null;
int num = 0;
try {
conn = JdbcUtil.open();
String sql = "delete from student where sid = ?";
stmt = conn.prepareStatement(sql);
//赋值
stmt.setInt(1, sid);
//执行
num = stmt.executeUpdate();
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(null, stmt, conn);
}
return num;
}
}
测试类:
public static void main(String[] args) {
Student s1 = new Student("zhangsan", "女", 19);
StudentDao dao = new StudentDao();
// int num = dao.save(s1);
// System.out.println("新增:"+num);
// int num2 = dao.delete(7);
// System.out.println("删除:"+num2);
// Student s2 = new Student(6, "zhangsan", "女", 19);
// int num3 = dao.update(s2);
// System.out.println("更新:"+num3);
List<Student> list = dao.findAll();
System.out.println(list.toString());
Student s3 = dao.findOne(9);
System.out.println(s3 == null ? "该对象不存在" :s3.toString());
}
Student的javaBean:
package com.lanou.bean;
/*
* 类---表
* 属性---字段
* 属性类型---字段类型
* int int
* String char/varchar
* Date date/datetime
* TimeStamp timestamp
*/
public class Student {
private int sid;
private String sname;
private String ssex;
private int sage;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSsex() {
return ssex;
}
public void setSsex(String ssex) {
this.ssex = ssex;
}
public int getSage() {
return sage;
}
public void setSage(int sage) {
this.sage = sage;
}
public Student(int sid, String sname, String ssex, int sage) {
super();
this.sid = sid;
this.sname = sname;
this.ssex = ssex;
this.sage = sage;
}
public Student() {
super();
}
public Student(String sname, String ssex, int sage) {
super();
this.sname = sname;
this.ssex = ssex;
this.sage = sage;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", ssex=" + ssex + ", sage=" + sage + "]";
}
}
jdbc第三天
1、周报 解决周报问题
作业量稍大:必选+附加
技术点:
1)什么是javabean
java语言写的一个可重用的组件,成为javaBean。
写javaBean满足:公共的方法,对外部可见,让外部调用。具有无参构造方法。
一般来讲,类中有私有属性、提供私有属性的getter、setter方法、提供构造方法。
2)Statement和PreparedStatement
Statement : PreparedStatement ===== 父:子
select id,name from 表名;
一般来说,没有特殊要求时,都统一使用PreparedStatement,效率高、不用拼接sql,避免注入攻击。
如果表名、库名 ,列名需要动态传入时,不能使用预编译,只能采用sql拼接。
注入攻击
如何防止注入攻击
/*
* 对比Statement和PreparedStatement
* 1、Statement拼接sql
* 如果表名、列名、库名需要动态传入,必须选择拼接
* 2、PreparedStatement 如何防止注入攻击?
* 'zhangsan\' or \'1\'=\'1' 对传入的字符串中特殊字符,转义为普通字符
*/
//Statement 可以 拼接 表名、列名
public List<Student> listByName1(String tablename){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Student> list = new ArrayList<Student>();
try {
conn = JdbcUtil.open();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from "+tablename);
while(rs.next()) {
int sid = rs.getInt("sid");//列名 常用
String sname = rs.getString(2);//列索引 从1开始排
int sage = rs.getInt(3);//如果一个表中有100个列,索引没法数
String ssex = rs.getString(4);
Student stu = new Student(sid, sname, ssex, sage);
list.add(stu);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return list;
}
//PreparedStatement
public List<Student> listByName2(String tablename,String column){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<Student> list = new ArrayList<Student>();
try {
conn = JdbcUtil.open();
stmt = conn.prepareStatement("select ? from student");
stmt.setObject(1, column);
rs = stmt.executeQuery();
while(rs.next()) {
int sid = rs.getInt("sid");//列名 常用
String sname = rs.getString(2);//列索引 从1开始排
int sage = rs.getInt(3);//如果一个表中有100个列,索引没法数
String ssex = rs.getString(4);
Student stu = new Student(sid, sname, ssex, sage);
list.add(stu);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return list;
}
/*
* 注入攻击
*/
public List<Student> listByName3(String name){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Student> list = new ArrayList<Student>();
try {
conn = JdbcUtil.open();
stmt = conn.createStatement();
String sql = "select * from student where sname = '"+name+"'";
rs = stmt.executeQuery(sql);
while(rs.next()) {
int sid = rs.getInt("sid");//列名 常用
String sname = rs.getString(2);//列索引 从1开始排
int sage = rs.getInt(3);//如果一个表中有100个列,索引没法数
String ssex = rs.getString(4);
Student stu = new Student(sid, sname, ssex, sage);
list.add(stu);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return list;
}
/*
* 使用预编译 防止注入攻击
* 执行sql api
* 相同点:三种方法都可以执行sql
* 不同点:返回结果集不同
*
* 1、executeUpdate() int 返回的是受影响的数据行 增、删、改
* 2、executeQuery() ResultSet 返回的是查询的结果集
* 3、execute() boolean
* 查询: true if the first result is a ResultSetobject;
* 增删改: false if the first result is an updatecount or there is no result
*/
public List<Student> listByName4(String name){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<Student> list = new ArrayList<Student>();
try {
conn = JdbcUtil.open();
String sql = "select * from student where sname = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, name);
rs = stmt.executeQuery();
while(rs.next()) {
int sid = rs.getInt("sid");//列名 常用
String sname = rs.getString(2);//列索引 从1开始排
int sage = rs.getInt(3);//如果一个表中有100个列,索引没法数
String ssex = rs.getString(4);
Student stu = new Student(sid, sname, ssex, sage);
list.add(stu);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return list;
}
3)约束不熟练
给列添加约束,限制数据的输入,保证数据的完整性和一致性。
primary key 非空+唯一
forign key 参照其他表数据 一致性
unique 唯一 可以有一个null
not null 非空,不能为空值
default 设置默认值
4)sql 思路 多表联合查询
-- 统计学生学号、姓名和平均成绩
-- 列 和 表
student ,sc
-- 每个学生平均成绩 根据学号分组,得平均成绩
sid avg(score)
1 90
2 80
select sid ,avg(score)
from sc
group by sid;
select sname,sc2.* from student,(select sid ,avg(score)
from sc
group by sid) sc2
where student.sid = sc2.sid
select student.sid ,sname,avg(score)
from sc join student
on sc.sid = student.sid
group by sid;
5)子查询
-- 参加考试的学号和姓名
select distinct sid from sc;
select sid,sname from student where sid in (1,2,3);
select sid,sname from student where sid in (select distinct sid from sc);
-- 没有参加考试的学号和姓名
select sid,sname from student where sid not in (select distinct sid from sc);
6)左右外连接
内连接:
查找连个表匹配的数据,能够关联上的数据。
外连接:
student sid 1,2,3,4
score sid 1,2,3
左外:from A left outer join B
右外:from A right outer join B
7)索引的使用
不需要调用。
sql优化器自动调用。
-- 全表扫描 从第一条到最后一条依次匹配 数据量小效率高 10-100-1000 0.01s
表中数据 10000000000 10s 效率低
-- 索引查找 hash、tree 快速定位 数据量大、重复数据少
8)jdbc主要api
* 相同点:三种方法都可以执行sql
* 不同点:返回结果集不同
*
* 1、executeUpdate() int 返回的是受影响的数据行 增、删、改
* 2、executeQuery() ResultSet 返回的是查询的结果集
* 3、execute() boolean
* 查询: true if the first result is a ResultSetobject;
* 增删改: false if the first result is an updatecount or there is no result
*/
while(rs.next()) {
int sid = rs.getInt("sid");//列名 常用
String sname = rs.getString(2);//列索引 从1开始排
int sage = rs.getInt(3);//如果一个表中有100个列,索引没法数
String ssex = rs.getString(4);
Student stu = new Student(sid, sname, ssex, sage);
list.add(stu);
}
2、抽查作业
3、jdbc回顾
4、jdbc连接池
数据库连接池
数据库连接池介绍
数据库连接池技术与我们前面学的线程池技术有点类似。都是"池化"技术,核心思想都是通过缓存一部分资源,从而达到复用的目的,可以一定程度上避免每次使用都重复创建、销毁的过程,节省系统开销,提高程序性能。
目前市面上主流的数据库连接池技术有:
- DBCP
- c3p0
- Druid
c3p0连接池用法
本章以c3p0连接池技术为例讲解一下连接池的用法,其他连接池与此类似,可参考各自官方文档、示例代码。
-
添加连接池依赖包
将以下两个jar包添加到工程的构建路径中
- c3p0-0.9.5.4.jar
- mchange-commons-java-0.2.16.jar
-
编写c3p0配置文件
c3p0配置文件中允许我们配置一个默认数据源和多个命名数据源,可以在程序中指定加载哪个
在工程src根目录新建
c3p0-config.xml
文件,在其中填入以下内容<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/yanfa3</property> <property name="user">root</property> <property name="password">root</property> <property name="initialPoolSize">40</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">60</property> <property name="maxStatements">100</property> <property name="maxIdleTime">60</property> </default-config> <named-config name="mysql"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/yanfa3</property> <property name="user">root</property> <property name="password">root</property> <property name="initialPoolSize">40</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">60</property> <property name="maxStatements">100</property> <property name="maxIdleTime">60</property> </named-config> <named-config name="oracle"> <property name="driverClass">oracle.jdbc.OracleDriver</property> <property name="jdbcUrl">jdbc:oracle:thin:@//localhost:1521:SERVICENAME</property> <property name="user">root</property> <property name="password">root</property> <property name="initialPoolSize">40</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">60</property> <property name="maxStatements">100</property> <property name="maxIdleTime">60</property> </named-config> <named-config name="sqlserver"> <property name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> <property name="jdbcUrl">jdbc:sqlserver://localhost:1433;DatabaseName=yanfa3</property> <property name="user">root</property> <property name="password">root</property> <property name="initialPoolSize">40</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">60</property> <property name="maxStatements">100</property> <property name="maxIdleTime">60</property> </named-config> </c3p0-config>
可以将此文件保存一份,用的时候修改里面的参数
-
通过c3p0连接池获取连接
// 读取配置文件中的默认配置,获取数据源 DataSource ds = new ComboPooledDataSource(); // 读取配置文件中指定配置,获取数据源 DataSource ds = new ComboPooledDataSource("mysql"); // 通过数据源对象获取单个连接 Connection conn = ds.getConnection();
jdbcUtil工具类:
package com.lanou.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/*
* 打开连接
* 关闭连接
*/
public class JdbcUtil {
// private static final String url = "jdbc:mysql://localhost:3306/studentmanage?useSSL=false";
// private static final String username = "root";
// private static final String password = "123456";
private static Connection conn = null;
private static DataSource ds = null;
static {
//1、加载驱动类
// try {
// Class.forName("com.mysql.jdbc.Driver");
// } catch (ClassNotFoundException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
ds = new ComboPooledDataSource();
}
public static Connection open() {
try {
// conn = DriverManager.getConnection(url,username,password);
conn = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(ResultSet rs,Statement stmt,Connection conn) {
//6、关闭资源、释放连接 先开的后关
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
5、补充内容
返回自增主键(前提是insert语句)
executeUpdate(sql—insert 、update、delete)
insert新增数据时,没有指定主键,新增成功后,返回当前新增数据行的主键。
update更新数据,一般是通过主键字段,更新其他字段。
(任意表student,新增姓名、性别,返回当前sid)
/*
* 返回自增主键
*/
public int save(Student student) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
int num = 0;
try {
conn = JdbcUtil.open();
String sql = "insert into student(sname,ssex) values (?,?)";
//返回主键值
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
stmt.setString(1, student.getSname());
stmt.setString(2, student.getSsex());
//执行sql
int num1 = stmt.executeUpdate();//新增、更新数据行数
//返回主键
rs = stmt.getGeneratedKeys();
//获取结果集 一行一列
if(rs.next()) {
num = rs.getInt(1);//获取第一列的值 1索引位置为第一列
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return num;
}
写c3p0连接池模式下完成增删改查时常见错误:
1、引入jar包 3个
mysql.jar 、mchange、c3p0
2、连接池配置文件 目前只能放在 src目录下,不能在src子目录中,而且文件名必须是c3p0-config.xml
3、c3p0-config.xml 配置文件内容
事务
四个特性:acid 原子性、一致性、隔离性、持久性
使用步骤:
1、设置自动提交模式关闭
2、开始事务
3、执行dml操作(insert、update、delete)
4、提交或者回滚事务
5、设置到默认自动提交模式
public void doWork(){
取消事务的自动提交机制,设置事务为手动提交.
Connection对象.setAutoCommit(false);
try{
操作1: 保存数据到订单表
操作2: 保存产品数据到订单详情表
-------------停电--------------
操作3: 更新库存
提交事务
Connection对象.commit();
}catch(Exception e){
回滚事务,取消之前所有的操作
Connection对象.rollback();
}finally{
释放资源
}
}
示例:
/*
* 先新增、再更新
*/
public int saveAndUpdate(Student student) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
int num = 0;
try {
//获取连接
conn = JdbcUtil.open();
//设置自动提交模式关闭
conn.setAutoCommit(false);
String sql = "insert into student(sname,ssex) values (?,?)";
//返回主键值
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
stmt.setString(1, student.getSname());
stmt.setString(2, student.getSsex());
//执行sql
int num1 = stmt.executeUpdate();//新增、更新数据行数
//返回主键
rs = stmt.getGeneratedKeys();
//获取结果集 一行一列
if(rs.next()) {
num = rs.getInt(1);
}
//新增成功后,更新当前主键对应的age
String sql2 = "update student set sage = ? where sid = ?";
stmt = conn.prepareStatement(sql2);
stmt.setInt(1, student.getSage());
stmt.setInt(3, num);//3是为了模拟失败情况
stmt.executeUpdate();
//提交事务
conn.commit();
}catch(Exception e) {
try {
//回滚事务
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
return num;
}
批处理
批量操作(新增)
前端 List 全部新增到数据库表中。
录入30个用户,提交到数据库中。
每次提交一个 录入一个、按钮提交。
一次性录入30行,按钮同时保存。
//测试,模拟数据
public void test(){
//模拟30个用户
List<Student> list = new ArrayList();
for(int i=0;i<30;i++) {
Student student = new Student("wang"+i, "男", 15+i);
list.add(student);
}
long startTime = System.currentTimeMillis();
dao.saveBatch2(list);
System.out.println(System.currentTimeMillis()-startTime);
}
/**
* 普通循环新增30行
* @param list
*/
public void saveBatch(List<Student> list) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
//获取连接
conn = JdbcUtil.open();
String sql = "insert into student(sname,ssex,sage) values (?,?,?)";
stmt = conn.prepareStatement(sql);
for(int i = 0;i<list.size();i++) {
Student s = list.get(i);
stmt.setString(1, s.getSname());
stmt.setString(2, s.getSsex());
stmt.setInt(3, s.getSage());
stmt.executeUpdate();
}
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
}
/**
* 批处理 1千万行
* 避免1行1提交对数据库服务器造成过大的压力
* 可以选择批量提交 比如:500行提交一次
*/
public void saveBatch2(List<Student> list) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
//获取连接
conn = JdbcUtil.open();
String sql = "insert into student(sname,ssex,sage) values (?,?,?)";
stmt = conn.prepareStatement(sql);
for(int i = 0;i<list.size();i++) {
Student s = list.get(i);
stmt.setString(1, s.getSname());
stmt.setString(2, s.getSsex());
stmt.setInt(3, s.getSage());
stmt.addBatch();//添加当前语句到批处理操作中
if(i%10==0) {
stmt.executeBatch();//执行批处理操作
//清除问号占位符
stmt.clearParameters();
stmt.clearBatch();
}
}
stmt.executeBatch();//执行批处理操作
}catch(Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(rs, stmt, conn);
}
}
6、自己封装jdbc工具方法(类型与框架封装)
jdbc 分页 和 高级搜索 servlet+jdbc整合讲。