1.JDBC简介
-
jdbc(Java DataBase Connectivity)
在C语言的Odbc基础上发展而来,是最早的ORM(Object Relation Mapping对象映射关系)工具,可以使用面向对象的Java代码
对关系型数据库进行操作。
ORM工具随着不断的发展衍生出了很多框架那么大部分框架都是在JDBC基础上发展而来,JDBC是几乎所有框架的基础,也是效率最高的ORM工具
JDBC是第一方技术,所有的接口等全部放置在java.sql包中全手动 JDBC
半自动 myBatis
全自动 Hibernate1)创建关系表
2)创建实体类
A:一般放置在com.etoak.po包中或者bean包中
B:尽量使用包装类封装字段,字段名对应
C:必须书写空参构造方法,酌情覆盖有参构造方法
D:酌情覆盖toString()
3)创建工厂类
A:工厂类一般放置在com.etoak.factory包中,此类链接数据库
B:加载驱动,只需要加载一次放置在静态初始化块中
C:封装一个方法返回链接
4)书写dao层
A:dao层全部放置在com.etoak.dao包中
B:接口用来设置需要被实现的方法
C:实现类实现接口中的方法
创建数据表
DROP table if EXISTS person;
CREATE table person (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10) NOT NULL,
pass VARCHAR(10) NOT NULL,
age INT,
salary DOUBLE,
birth DATE
);
insert INTO person VALUES (null,'elena','12345',20,5000.00,'1990-06-03');
insert INTO person VALUES (null,'penny','123465',30,6000.00,'1993-06-13');
insert INTO person VALUES (null,'aleric','1234545',40,7000.00,'1992-06-05');
insert INTO person VALUES (null,'bonnie','1432345',20,3000.00,'1996-06-03');
insert INTO person VALUES (null,'matt','123345',24,15000.00,'1997-06-04');
insert INTO person VALUES (null,'damon','123445',23,25000.00,'1992-06-04');
insert INTO person VALUES (null,'用户名','1232245',29,5000.00,'1998-07-01');
1. JavaBean实体类
如果一个Java类仅仅封装了属性,没有其他方法,则称之为POJO类或实体类,好像也叫作JavaBean,通常放置在com.xxx.po 或者 com,xxx.bean 包中
这个类中封装的属性必须对用数据库中的字段,必须覆盖空参的构造方法,酌情覆盖全参构造方法,酌情覆盖toString()方法
public class Person{
//使用包装类封装字段,必须对应表中的字段
private Integer id;
private String name;
private String pass;
private Integer age;
private Double salary;
private Date birth;
/*
* 必须覆盖空参的构造方法
* 覆盖空参构造方法之后可以new空参的对象
* Person per = new Person();
* */
public Person() {
}
/*
* 酌情覆盖全参构造方法,这样我们就可以直接new一个带有六个参数的对象
* Person per = new Person(XX,XX,XX,XX,XX,XX);
* */
public Person(Integer id, String name, String pass, Integer age, Double salary, Date birth) {
this.id = id;
this.name = name;
this.pass = pass;
this.age = age;
this.salary = salary;
this.birth = birth;
}
//各个属性的get和set方法
//看需求是否覆盖 toString() 方法
}
2. 工厂类
- 一般放置在**com.xxx.factory包中**
1.加载驱动
static{
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(Exception e){
e.printStackTrace();
}
}
2.获取链接
public static Connection getConn(){
try{
//2.加载链接
/*
* 完全版:
* jdbc:mysql://localhost:端口号/database
* jdbc:mysql://远程ip地址:端口号/database
* 如果数据库在本地,则可以使用简化版:
* jbdc:mysql:///database
* user:用户名
* password:用户密码
* */
return DriverManager.getConnection("jdbc:mysql:///et1912","root","dream");
}catch(Exception e){
e.printStackTrace();
return null;
}
}
3.释放资源
public static void close(ResultSet rs, Statement st,Connection con){
try {
if(rs!=null)
rs.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(st!=null)
st.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(con!=null)
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
代码
package com.etoak.factory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Factory {
/*
* A:加载驱动
* 不同的数据库品牌厂商提供了不同的驱动,可以正确识别各种厂商的数据库品牌
* 语法等,加载驱动之后,在Java端可以使用相同的Java代码操作不同品牌不同语法的数据库
此处使用静态初始化块仅仅加载一次即可
* */
static{
try {
//使用反射类加载的方式加载驱动
//不同品牌的驱动不同,需要导入数据库厂商提供的jar包
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception ex) {
ex.printStackTrace();
}
}
/*
* B:获取连接
* 连接数据库,通过驱动管理器提供连接地址,用户名和密码可以链接数据库
* */
public static Connection getCon(){
try {
/*
* 注意这里三个参数分别是
* url:链接地址
* 格式完全版
* jdbc:mysql://localhost:8080/数据库名
* jdbc:mysql://远程ip地址:8080/数据库名
* 如果数据库就在本地,则可以使用简化版
* jdbc:mysql:///数据库名
* user:用户名
* password:密码
* */
return DriverManager.getConnection(
"jdbc:mysql:///et1912","root","etoaketoak");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/*
* C:释放资源
* 释放资源时顺序如下:
* 首先关闭结果集,关闭执行器,最后关闭连接
* */
public static void close(ResultSet rs, Statement st,Connection con){
try {
if(rs!=null)
rs.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(st!=null)
st.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(con!=null)
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
}
3.dao持久化层
- dao(Data Access Object) 数据访问对象
- 通常放置在**com.xxx.dao包下**
1. 接口
/*
* Dao:Data Access Object数据访问对象
* 这里的接口一般由项目经理或者一些规范的制定者来执行
* 如何实现不关心,仅仅提供了一个规范
* DaoIf 是DaoInterface的简写
* */
public interface PersonDaoIf {
//添加一个用户
public boolean addPerson(Person per);
//根据id删除一个用户
public boolean delPersonById(Integer id);
//拿取全部用户
public List<Person> queryAll();
//根据用户名查询
public boolean queryName(String name);
//根据用户名和密码查询
public Person queryPerson(String name,String pass);
//修改用户资料
public boolean updatePerson(Person per);
}
public interface PersonDaoIf2 {
//1添加用户
public boolean addPerson(Person per);
//2根据id删除
public boolean delPersonById(Integer id);
//3根据name删除
public boolean delPersonByName(String name);
//4拿取全部
public List<Person> queryAll();
//5姓名查重
public boolean queryName(String name);
//6登录查询
public Person queryPerson(String name,String pass);
//7拿取总记录数
public Integer queryCount();
//8分页查询
public List<Person> queryPage(Integer index,Integer max);
//9姓名模糊分页查询
public List<Person> queryNameLikePage(String args,Integer index,Integer max);
//10条件分页查询
public List<Person> queryLikePage(Person per,Integer index,Integer max);
//11批量删除
public boolean multiDel(String[] args);
//12修改
public boolean updatePerson(Person per);
}
2.接口实现类[Statement]
- 创建 PersonDaoIf 接口的实现类 PersonDaoImpl
- 右键空白处 **(或者alt + insert)**选择 Implements Method,实现接口中的抽象方法
public class PersonDaoImpl implements PersonDaoIf{
//设置连接
Connection conn;
//设置执行器
Statement st;
//结果集
ResultSet rs;
@Override
public boolean addPerson(Person per) {
try {
//书写sql语句
/*
* java.util.Date无法和字符串直接通过+拼接成sql语句
* 可以有以下两种方式
* 1)将java.util.Date转换为java.sql.Date,可以直接拼接
* 2)将java.util.Date转换为字符串
*
*
* */
String sql =
"insert into person values (null,'"+per.getName()+"','"+per.getPass()+"',"+per.getAge()+","
+per.getSalary()+",'"+new SimpleDateFormat("yyyy-MM-dd").format(per.getBirth()) +"')";
//获取连接
con = Factory.getCon();
//拿取执行器
st = con.createStatement();
//执行器根据sql语句调用方法
return st.executeUpdate(sql)==1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
//不管是否执行正常都要释放资源
Factory.close(null,st,con);
}
}
}
存在的安全隐患
- 当传入的是一个恒等的条件表达式的时候,语句相当于查找全表数据
- 可以被SQL注入
3.接口实现类[PreparedStatement]
- 创建类PersonDaoImpl2实现PersonDaoIf2接口
- PreparedStatement是Statement的子类
- 使用PreparedStatement执行器时,使用 ? 先进行站位,后填充
- 填充日期类型时,需要用**new java.sql.Date(xxx.getDate().getTime())**
package com.etoak.dao;
import com.etoak.factory.Factory;
import com.etoak.po.Person;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class PersonDaoImpl2 implements PersonDaoIf2 {
Connection con;
Statement st;
/*
* 使用执行器PreparedStatement,它是Statement的子类
* */
PreparedStatement pst;
ResultSet rs;
@Override
public boolean addPerson(Person per) {
try {
/*
* 在使用Statement时,需要我们对sql语句进行拼接,但是在进行拼接时非常的不方便,
* 并且安全性较低,容易出现sql注入安全隐患
* 使用PreparedStatement则可以使用?作为占位符的形式来组装sql语句,不再需要我们
* 进行复杂的sql拼接了
*
* 注意使用?占位,必须填充占位符,因为sql语句中不能再执行时存在?
* */
String sql = "insert into person values (null,?,?,?,?,?)";
con = Factory.getCon();
//获取执行器的同时,加载带有?占位符的sql语句
pst = con.prepareStatement(sql);
//由于存在占位符所以必须填充
/*
* pst.set数据类型(index,要填充的值)
* index:表示从左往右?的顺序,注意从1开始
* */
pst.setString(1,per.getName());
pst.setString(2,per.getPass());
pst.setInt(3,per.getAge());
pst.setDouble(4,per.getSalary());
/*
* java.util.Date和java.sql.Date的区别
*
* 1)java.util.Date是sql.Date的父类
* 2)util.Date一般可以设置年月日小时分钟秒
* 而sql.Date只能精确到年月日
* 3)util.Date不能和字符串直接拼接成sql语句
* 而sql.Date可以
* 4)通过getTime()进行转换
* */
pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
return pst.executeUpdate()==1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
//长按ctrl或者command键可以溯源
Factory.close(null,pst,con);
}
}
@Override
public boolean delPersonById(Integer id) {
try {
String sql = "delete from person where id = ?";
con = Factory.getCon();
//获取执行器的同时加载sql语句
pst = con.prepareStatement(sql);
pst.setInt(1,id);
return pst.executeUpdate()==1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
Factory.close(null,pst,con);
}
}
@Override
public boolean delPersonByName(String name) {
try {
String sql = "delete from person where name = ?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
pst.setString(1,name);
return pst.executeUpdate()>=1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
Factory.close(null,pst,con);
}
}
@Override
public List<Person> queryAll() {
try {
String sql = "select * from person";
con = Factory.getCon();
pst = con.prepareStatement(sql);
rs = pst.executeQuery();
List<Person> list = new ArrayList<>();
while(rs.next()){
list.add(new Person(rs.getInt(1),
rs.getString(2),rs.getString(3),rs.getInt(4)
,rs.getDouble(5),rs.getDate(6)));
}
return list;
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
Factory.close(rs,pst,con);
}
}
@Override
public boolean queryName(String name) {
try {
String sql = "select * from person where name = ?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
pst.setString(1,name);
return pst.executeQuery().next();
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
Factory.close(rs,pst,con);
}
}
@Override
public Person queryPerson(String name, String pass) {
try {
String sql = "select * from person where name = ? and pass = ?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
pst.setString(1,name);
pst.setString(2,pass);
rs = pst.executeQuery();
if(rs.next()){
return new Person(rs.getInt(1),
rs.getString(2),rs.getString(3)
,rs.getInt(4),rs.getDouble(5),rs.getDate(6));
}
return null;
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
Factory.close(rs,pst,con);
}
}
@Override
public Integer queryCount() {
try {
String sql = "select count(*) from person";
con = Factory.getCon();
pst = con.prepareStatement(sql);
rs = pst.executeQuery();
/*
* 这里的rs返回的是一个两行一列的表格
* ------------
* | |
* | count |
* ------------
* | |
* | 记录数 |
* ------------
*
* 指针指向表头,使其下移一行
*/
rs.next();
return rs.getInt(1);
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
Factory.close(rs,pst,con);
}
}
@Override
public List<Person> queryPage(Integer index, Integer max) {
try {
/*
* select 字段 from 表 limit x,y;
* x:表示起始索引值
* y:表示显示几条记录
* */
String sql = "select * from person limit ?,?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
pst.setInt(1,index);
pst.setInt(2,max);
rs = pst.executeQuery();
List<Person> list = new ArrayList<>();
while(rs.next()){
list.add(new Person(rs.getInt(1),
rs.getString(2),
rs.getString(3),
rs.getInt(4),
rs.getDouble(5),
rs.getDate(6)));
}
return list;
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
Factory.close(rs,pst,con);
}
}
//根据姓名模糊查询并且分页
@Override
public List<Person> queryNameLikePage(String args, Integer index, Integer max) {
try {
String sql = "select * from person where name like ? limit ?,?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
//对左模糊右模糊进行拼接
pst.setString(1,"%"+args+"%");
pst.setInt(2,index);
pst.setInt(3,max);
rs = pst.executeQuery();
List<Person> list = new ArrayList<>();
while(rs.next()){
list.add(new Person(rs.getInt("id")
,rs.getString("name")
,rs.getString("pass")
,rs.getInt("age")
,rs.getDouble("salary")
,rs.getDate("birth")));
}
return list;
} catch (Exception ex) {
ex.printStackTrace();
return null;
} finally {
Factory.close(rs,pst,con);
}
}
@Override
public List<Person> queryLikePage(Person per, Integer index, Integer max) {
return null;
}
/*
* 此处传入的是字符串类型的数组,内部封装了所有的id
* 根据这些id批量删除,注意不需要考虑id的真实性情况
*
* */
@Override
public boolean multiDel(String[] args) {
try {
String sql = "delete from person where id in (";
String sum = "";
for(int i = 0;i<args.length;i++){
sum = args[i]+","+sum;
}
sum = sum.substring(0,sum.length()-1);
sql += sum+")";
con = Factory.getCon();
st = con.createStatement();
/*
* pst = con.preparedStatement(sql);
* pst.executeUpdate()>=1
* */
return st.executeUpdate(sql)>=1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
Factory.close(null,pst,con);
}
}
@Override
public boolean updatePerson(Person per) {
try {
String sql =
"update person set name = ?,pass = ?,age = ?,salary = ?,birth = ? where id = ?";
con = Factory.getCon();
pst = con.prepareStatement(sql);
pst.setString(1,per.getName());
pst.setString(2,per.getPass());
pst.setInt(3,per.getAge());
pst.setDouble(4,per.getSalary());
pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
pst.setInt(6,per.getId());
return pst.executeUpdate()==1;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
Factory.close(null,pst,con);
}
}
}
1.书写套路注意事项
- Statement执行器
//在实现的方法中,第一步现获取连接
conn = Factory.getConn();
//第二步,获取执行器
st = conn.createStatement();
//第三步。书写Sql语句,这里可以先将SQL语句写完整之后在根据是否是字符类型的加双引号
String sql = "select * from person";
//如果没有返回结果集,则返回执行结果,
//此方法返回的是受影响的行数,返回值为int
return st.executeUpdate(sql) > 0;
//如果有返回结果集,则第四步,获得结果集
rs = st.executeQuery(sql);
//第五步,创建一个新的空集合,给定泛型确保只能存储该类型的对象
List<Person> list = new ArrayList<>();
//第六步 把结果集中的结果依次添加到空集合中
while(rs.next()){
list.add(new Person(rs.getInt(1),...));
}
//第七步,关闭连接
Factory.closeConn(rs,st,conn);
- PreparedStatement执行器
//1获取连接
conn = Factory.getConn();
//2.书写sql语句,先使用占位符 ? 来填充
String sql = "select * from person where name like ? limit ?,?";
//3.获取执行器d的同时把sql语句传入
pst = conn.preparedStatement(sql);
//4.给占位符传入相应的值,第一个参数代表是sql语句中第几个问号,第二个参数代表传入的值
//4.1 模糊查询时拼接字符串
pst.setString(1,"%" + per.getName() + "%");
//4.2传入其他参数
pst.setInt(2,per.getAge());
//4.3 Date类型,因为util.Date不能拼接sql语句,所以要转化成sql.Date
pst.setDate(3,new java.sql.Date(per.getBirth().getTime()));
//5.执行
pst.executeQuery();
2. Date注意事项
- 执行sql语句拼接Date时
- java.util.Date无法和字符串直接通过+拼接成sql语句
可以有以下两种方式
1)将java.util.Date转换为java.sql.Date,可以直接拼接
2)将java.util.Date转换为字符串
String sql = "insert into person values('"+ new SimpleDateFormat("yyyy-MM-dd").format(Date) +"')"
- 创建对象把String转换成Date类型时
Person per = new Person(new SimpleDateFormat("yyyy-MM-dd").parse("1999-01-01"));
- PreparedStatement传入Date
pst = conn.preparedStatement(sql);
pst.setDate(1,new java.sql.Date(per.getBirth().getTime()));
4. 测试
package com.etoak.test;
import com.etoak.factory.Factory;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class Test {
public static void main(String[] args) {
try {
//调用工厂获取连接,从而链接数据库
Connection con = Factory.getCon();
/*
* 如果出现Can not found class com.mysql.jdbc.Driver则是没导包
* 或者驱动书写错误
* */
if(con==null){
System.out.println("链接失败!!");
return;
}
System.out.println("链接成功!!");
/*
* 获取连接之后可以获取执行器,执行器用来执行SQL语句
* 主要有以下两种执行器
* Statement
* PreparedStatement
* */
Statement st = con.createStatement();
String dml1 = "insert into person values (null,'测试1','12345',30,2000.00,'2000-03-03')";
String dql1 = "select * from person";
/*
* 获取执行器之后可以根据SQL语句类型的不同,调用以下几种方法
*
* 1) boolean execute()
* 如果执行DQL语句,则返回true
* 如果执行DML语句,则返回false,但是依然可以执行
* 此方法使用较少
*
* 2) int executeUpdate()
* 如果执行DQL语句,立刻报错
* 如果执行DML语句,则返回更改的记录数
*
* 3) ResultSet executeQuery()
* 如果执行DML语句,立刻报错
* 执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值
*
*
* 4) int[] executeBatch()
* 执行批处理,一次执行多条SQL语句
* */
//int count = st.executeUpdate(dml1);
//System.out.println(count);
ResultSet rs = st.executeQuery(sql1);
/*
* 要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析
不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格
存在表头,永远不为null
存在一个 boolean next() 结果集类似一个表格,默认指针指向第一行表头,当我们调用
.next()时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false
所以我们可以根据.next()方法是否返回true来判断是否存在有效数据
* */
while(rs.next()){
/*
* 拿取数据:
* get数据类型(列数)或者get数据类型(列名)
* */
/*System.out.println("ID:"+rs.getInt(1)+"\t姓名:"+rs.getString(2)
+"\t密码:"+rs.getString(3)+"\t年龄:"+rs.getInt(4)+"\t薪资:"
+rs.getDouble(5)+"\t生日:"+rs.getDate(6));*/
System.out.println("ID:"+rs.getInt("id")+"\t姓名:"
+rs.getString("name")+"\t密码:"+rs.getString("pass")
+"\t年龄:"+rs.getInt("age")+"\t薪资:"+rs.getDouble("salary")
+"\t生日:"+rs.getDate("birth"));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
1. 注意点
- 创建执行器
- 通常有两种 Statement , PreparedStatement
返回类型 | 执行器方法 | 解释 |
---|---|---|
boolean | execute() | 如果执行DML语句则返回true 如果执行DML语句,则返回false,但是依然可以执行 此方法使用较少 |
int | executeUpdate() | 如果执行DQL语句立即报错 执行DML语句则返回受影响的记录数 |
ResultSet | executeQuery() | 如果执行DML语句立即报错 执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值 |
int[] | executeBatch() | 执行批处理,一次执行多条SQL语句 |
语言 | 全称 | 包含内容 |
---|---|---|
SQL | Structured Query Language,结构化查询语言 | DDL、DML、DQL、DCL、TCL |
DDL | Data Definetion Language,数据定义语言 | create(新建)、alter(修改)、drop(删除)、truncate(截断) |
DML | Data Manipulation Language,数据操纵语言 | insert (插入)、update(修改)、delete(删除) |
DQL | Data Query Language,数据查询语言 | select(查询) |
DCL | Data Control Language数据控制语言 | grant(授权)、revoke(取消授权) |
TCL | Translation Control Language事务控制语言 | commit(提交)、rollback(回滚)、savepoint(保存还原点),只会影响DML操作。 |
- 拿取有效数据
要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析
不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格, 存在表头,永远不为null, 存在一个 boolean next() 结果集类似一个表格,
默认指针指向第一行表头,当我们调用 rs .next() 时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false所以我们可以根据.next()方法是否返回true来判断是否存在有效数据
rs = st.executeQuery(sql);
while(rs.next()){
//TODO
}
- 拿取数据
- 可以通过 get数据类型(列数) 或者 get数据类型(列名)来拿取
Integer id = rs.getInt(1);
String name = rs,getString("name");
2.执行器的executeBatch()方法
- 首先需要关闭mysql的自动提交事务,conn.setAutoCommit(false); 出错时不会提交
- 用 addBatch(sql)方法 把要执行的SQL语句挨个放进执行器中
- 执行方法并提交
- 打开MySQL的自动提交
public class TestBatch {
public static void main(String[] args) {
try {
//获取连接
Connection con = Factory.getCon();
//关闭mysql的自动提交事务
con.setAutoCommit(false);
//获取执行器
Statement st = con.createStatement();
//设置要批处理得sql
//注意批处理不能执行dql语句
String dml1 = "insert into person values (null,'elena','12345',30,5000.00,'1990-03-01')";
String dml2 = "insert into person values (null,'damon','33345',20,6000.00,'1993-03-01')";
String dml3 = "insert into person values (null,'stefan','53345',17,4000.00,'1992-03-01')";
String dml4 = "delete from person where id = 1";
//将要执行的sql语句添加进缓存中
//这里每条sql语句都类似一个子弹,此处压入弹夹
st.addBatch(dml1);
st.addBatch(dml2);
st.addBatch(dml3);
st.addBatch(dml4);
//进行批处理操作
/*
* 返回的是一个int类型的数组,内部封装了更改的记录数
*
* */
int[] count = st.executeBatch();
//提交事务
con.commit();
//恢复自动提交
con.setAutoCommit(true);
for(int i:count){
System.out.println("更改的记录数是~~~~》"+i);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
5. 🐴Statement和PreparedStatement的区别
- 相同点
两者都为接口
public interface Statement implements Wrapper
public interface PreparedStatement implements Statement PreparedStatement是Statement的子类
- 不同点
①:Statem只能执行静态语句; PreparedStatement 可以还行IN参数的sql语句,所谓IN参数是指,sql语句可以进行字段等数据的更改
并不是一个固定的语句。②PreparedStatement存在一个强大缓存区,可以对sql语句
进行预编译,在执行相同的sql语句时,PreparedStatement
将语句加载进缓存区,仅仅编译一次,当第二次执行此语句时
不需要再次进行编译,也就是说相同的sql语句执行多条
仅仅编译一次,PreparedStatement仅对改动数据进行修改
而不再进行编译;
Statement只要语句发生了改变,则必须重新进行编译③:PreparedStatement支持对sql语句使用?占位符,从而对
sql语句进行字段参数的修改,降低了开发难度,并且从根本上杜绝了
sql注入安全隐患④如果sql语句不需要多次执行,或者?过多,则效率可能较
Statement低