jdbc 批量insert_037 深入JDBC中PreparedStatement对象使用
1. 什么是SQL注入
(1) 什么是SQL注入?
所谓SQL注入,就是通过把含有SQL语句片段的参数插入到需要执行的SQL语句中,最终达到欺骗数据库服务器执行恶意操作的SQL命令。
(2) 如何解决SQL注入问题?
使用PreparedStatement可防止出现SQL注入问题
2. 通过PreparedStatement对象完成数据的新增
(1) PreparedStatement有哪些特点?
preparedStatement特点:
PreparedStatement接口继承Statement接口
效率高于Statement
支持动态绑定参数
具备SQL语句预编译能力
使用PreparedStatement可防止出现SQL注入问题
3. 什么是预编译
(1) 数据库中SQL执行的步骤是什么?
语法和语义解析-->优化sql语句,制定执行计划-->执行并返回结果
但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同( 比如select的where子句值不同,update的set子句值不同,insert的values值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化。
预编译语句的优势在于:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。
(2) 什么是硬解析?
在不开启缓存执行计划的情况下,每次SQL的处理都要经过:语法和语义的解析,优化器处理SQL,生成执行计划。整个过程我们称之为硬解析。
(3) 什么是软解析?
如果开启了缓存执行计划,数据库在处理SQL时会先查询缓存中是否含有与当前SQL语句相同的执行计划,如果有则直接执行该计划。
(4) 如何依赖数据库驱动完成预编译?
如果我们没有开启数据库服务器端编译,那么默认的是使用数据库驱动完成SQL的预编译处理。
一般我们选择依赖数据库驱动完成预编译。主要是为了减少服务器端的负担。
(5) 如何依赖数据库服务完成预编译?
我们可以通过修改连接数据库的URL信息,添加userServerPrepStmts=true信息开启服务器端预编译。
查看通用日志的开启状态:show variables like ‘%general_log%’
将日志设置为开启状态:set global general_log = on
设置日志输出级别:set global log_output = ‘table’
4. 通过PreparedStatement对象完成数据的更新
(1) 通过使用PreparedStatement对象更新一条departments表中的数据。
public void updateDepartments(int departmentId,String departmentName,int locationId) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement("update departments set department_name=?,location_id=? where department_id=?");
ps.setString(1, departmentName);
ps.setInt(2, locationId);
ps.setInt(3, departmentId);
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn);
}
}
5. 通过PreparedStatement对象完成数据的查询
(1) 通过PreparedStatement对象查询departments表中的数据。
//通过PreparedStatement对象来查询表中数据
public void selectDepartments(int departmentId) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
ps=conn.prepareStatement("select * from departments where department_id=?");
ps.setInt(1, departmentId);
rs=ps.executeQuery();
while(rs.next()) {
System.out.println(rs.getInt("department_id")+"t"+rs.getString("department_name")+"t"+rs.getInt("location_id"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn, rs);
}
}
6. PreparedStatement对象查询数据时like的使用
(1) 查询部门表中的部门名称,找到那些包含“人力”的部门信息。
通过like关键字对数据库进行查询:
//用部门名称来获得相对的Departments对象
public ArrayList<Departments> getDepartmentsByName(String departmentName) {
ArrayList<Departments> list=new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement("select * from departments where department_name like ?");
ps.setString(1, "%"+departmentName+"%");
rs=ps.executeQuery();
while(rs.next()) {
Departments dept = new Departments();
dept.setDepartmentId(rs.getInt("department_id"));
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
list.add(dept);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
7. PreparedStatement对象的批处理操作
(1) 什么是SQL语句的批处理?
在一个方法内进行一条SQL语句的多次重复执行。
(2) 批量的向departments表中插入5条数据。
public void addButh(ArrayList<Departments> list) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement("insert into departments values(default,?,?)");
for(int i=0;i<list.size();i++) {
ps.setString(1, list.get(i).getDepartmentName());
ps.setInt(2, list.get(i).getLocationId());
ps.addBatch();
}
int[] arr=ps.executeBatch();
for(int i=0;i<arr.length;i++) {
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn);
}
}
//插入5条研发部的数据
ArrayList<Departments> list = new ArrayList<>();
for(int i=1;i<=5;i++) {
Departments dept = new Departments();
dept.setDepartmentName("研发部"+i);
dept.setLocationId(20+i);
list.add(dept);
}
psd.addButh(list);
//利用名字查询的方法得到插入的研发部的数据并输出
ArrayList<Departments> departments=psd.getDepartmentsByName("研发");
for (Departments departments2 : departments) {
System.out.println(departments2);
}
8. JDBC中的事务处理
(1) 删除departments表中的一条数据,事务提交方式为手动提交。
在JDBC操作中数据库事务默认为自动提交。如果事务需要修改为手动提交,那么我们需要使用Connection对象中的setAutoCommit方法来关闭事务自动提交。然后通过Connection对象中的commit方法与rollback方法进行事务的提交与回滚。
//根据like关键字,删除名称包含某字段的部门信息记录。设置手动提交。
public void deleteDepartments(String departmentName) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement("delete from departments where department_name like ?");
ps.setString(1, "%"+departmentName+"%");
conn.setAutoCommit(false);
ps.executeUpdate();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
JdbcUtil.closeResource(ps, conn);
}
}
//测试删除方法
psd.deleteDepartments("研发");
ArrayList<Departments> departments=psd.getDepartmentsByName("研发");
for (Departments departments2 : departments) {
System.out.println(departments2);
}
一般我们涉及到DML操作时,都设置成手动提交。
9. 动态SQL查询
(1) 什么是动态查询?
根据用户给定的条件来决定执行什么样的查询。
public class JDBCAdvanced {
//动态查询
public List<Departments> selectDeptByProperty(Departments department) {
Connection conn = null;
PreparedStatement ps=null;
ResultSet rs = null;
List<Departments> list=new ArrayList<>();
try {
conn=JdbcUtil.getConnection();
String sql = genSQL(department);
System.out.println(sql);
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while(rs.next()) {
Departments dept = new Departments();
dept.setDepartmentId(rs.getInt("department_id"));
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
list.add(dept);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn, rs);
}
return list;
}
//封装根据传入的Departments对象来生成对应的sql语句的方法
private String genSQL(Departments dept) {
StringBuffer sb = new StringBuffer();
sb.append("select * from departments where 1=1 ");//1=1永远成立,解决了语句拼接中where 与 and的连接问题
if(dept.getDepartmentId()>0) { //当部门号大于0时说明有值
sb.append(" and department_id = ").append(dept.getDepartmentId());
}
if(dept.getDepartmentName()!=null&&dept.getDepartmentName().length()>0) {//当部门名称不为空且长度大于0时,说明有名称
sb.append(" and department_name = '").append(dept.getDepartmentName()).append("'");
}
if(dept.getLocationId()>0) {
sb.append(" and location_id = ").append(dept.getLocationId());
}
return sb.toString();
}
//测试
public static void main(String[] args) {
JDBCAdvanced ad = new JDBCAdvanced();
Departments department=new Departments();
department.setDepartmentId(7);
List<Departments> list=ad.selectDeptByProperty(department);
for (Departments departments : list) {
System.out.println(departments);
}
}
}
10. 什么是应用程序分层
(1) 什么是应用程序分层?
应用程序通过创建不同的包来实现项目的分层,将项目中的代码根据功能做具体划分,并存放在不同的包下。
(2) 分层有哪些优点?
1-分层结构将应用系统划分为若干层,每一层只解决问题的一部分,通过各层的协作提供整体解决方案。大的问题被分解为一系列相对独立的子问题,局部化在每一层中,这样就有效的降低了单个问题的规模和复杂度,实现了复杂系统的第一步也是最为关键的一步分解。
2-分层结构具有良好的可扩展性,为应用系统的演化增长提供了一个灵活的支持,具有良好的可扩展性。增加新的功能时,无须对现有的代码做修改,业务逻辑可以得到最大限度的重用。
3-分层架构易于维护。在对系统进行分解后,不同的功能被封装在不同的层中,层与层之间的耦合显著降低。因此在修改某个层的代码时,只要不涉及层与层之间的接口,就不会对其他层造成严重影响。
(3) 三层结构指的是什么?
三层结构就是将整个业务应用划分为:界面层(User Interface Layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。
11. 应用程序分层的设计及使用
(1) 创建一个新项目,按照应用程序分层方式实现对departments表的CRUD操作。
在分层业务中实现业务
持久层
代码:
接口:
public interface DepartmentsDao {
//按照名字查找部门信息
public List<Departments> selectDeptByName(String deptName);
//插入部门信息
public void insertDept(Departments dept);
}
持久层接口实现类:
public class DepartmentDaoImpl implements DepartmentsDao{
@Override
public List<Departments> selectDeptByName(String deptName) {
List<Departments> list = new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement("select * from departments where department_name = ?");
ps.setString(1, deptName);
rs=ps.executeQuery();
while(rs.next()) {
Departments dept = new Departments();
dept.setDepartmentId(rs.getInt("department_id"));
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
list.add(dept);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn, rs);
}
return list;
}
@Override
public void insertDept(Departments dept) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn=JdbcUtil.getConnection();
conn.setAutoCommit(false);
ps=conn.prepareStatement("insert into departments values(default,?,?)");
ps.setString(1, dept.getDepartmentName());
ps.setInt(2, dept.getLocationId());
ps.executeUpdate();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
JdbcUtil.closeResource(ps, conn);
}
}
}
业务层代码:
接口:
public interface DepartmentsService {
public void addDept(Departments dept);
}
实现类:
public class DepartmentsServiceImpl implements DepartmentsService{
@Override
public void addDept(Departments dept) {
DepartmentsDao dao = new DepartmentDaoImpl();
dao.insertDept(dept);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Departments dept = new Departments();
dept.setDepartmentName("技术测试部");
dept.setLocationId(20);
DepartmentsService ds = new DepartmentsServiceImpl();
ds.addDept(dept);
}
}
BaseDao通用DML操作接口:
public interface BaseDao {
public int executeUpdate(String sql,Object[] params);
}
对应的实现类:
public class BaseDaoImpl implements BaseDao{
@Override
public int executeUpdate(String sql, Object[] params) {
Connection conn = null;
PreparedStatement ps = null;
int rows=0;
try {
conn = JdbcUtil.getConnection();
conn.setAutoCommit(false);
ps=conn.prepareStatement(sql);
ParameterMetaData pmd = ps.getParameterMetaData(); //通过PreparedStatement的ParameterMetaData对象来获取?的个数
for(int i=0;i<pmd.getParameterCount();i++) {
ps.setObject(i+1, params[i]); //遍历赋值
}
rows=ps.executeUpdate(); //将执行的条数返回
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
JdbcUtil.closeResource(ps, conn);
}
return rows;
}
}
所有的DAO实现类都要继承这个BASEDAO的实现类。具体数据库操作层面实现类实现具体的SQL语句编写和参数赋值。供服务类用户使用该方法。
//更新数据库数据
@Override
public int updateDept(Departments dept) {
String sql="update departments set department_name=?,location_id=? where department_id=?";
Object[] params = new Object[] {dept.getDepartmentName(),dept.getLocationId(),dept.getDepartmentId()};
return this.executeUpdate(sql, params);
}
封装通用的BaseDao来实现通用的查询方法
BaseDao接口
public <T> List<T> find(String sql,Object[] params,Class<T> clazz);
BaseDaoImpl接口实现类
/**
* 完成通用的查询方法
* <T> List<T> 泛型方法
* 注意:通用查询方法中要求对象模型的属性名必须要和数据库表中的列名相同。
*/
@Override
public <T> List<T> find(String sql, Object[] params, Class<T> clazz) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<T> list = new ArrayList<>();
try {
conn=JdbcUtil.getConnection();
ps=conn.prepareStatement(sql);
ParameterMetaData pmd = ps.getParameterMetaData(); //通过PreparedStatement的ParameterMetaData对象来获取?的个数
for(int i=0;i<pmd.getParameterCount();i++) {
ps.setObject(i+1, params[i]); //遍历赋值
}
//处理结果集
rs=ps.executeQuery();
ResultSetMetaData rsmd=rs.getMetaData();
while(rs.next()) {
//完成ORM处理,通过JDK的映射
T bean=clazz.newInstance();
for(int i=0;i<rsmd.getColumnCount();i++) {
//得到列名
String columnName = rsmd.getColumnName(i+1);
//获取列的值
Object value = rs.getObject(columnName);
//通过BeanUtils将值放到对象中
BeanUtils.setProperty(bean, columnName, value);
}
list.add(bean);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.closeResource(ps, conn,rs);
}
return list;
}
DepartmentDao接口
//通用查询部门信息方法
public List<Dept> selectDeptByLikeName(String deptName);
DepartmentDao接口实现类
@Override
public List<Dept> selectDeptByLikeName(String deptName) {
String sql = "select * from departments where department_name like ?";
Object[] params = new Object[] {"%"+deptName+"%"};
return this.find(sql, params, Dept.class);
}
JDBC驱动加载原理:
创建对象的方式:
使用new关键字:调用了构造函数
使用Class类的newInstance方法:调用了构造函数
使用Constructor类的newInstance方法:调用了构造函数
使用clone方法:没有调用构造函数
使用反序列化:没有调用构造函数
创建对象时三个重要的步骤:
通过类加载器加载class;
初始化所有静态部分;
为新生对象分配内存。
MySQL驱动类的实例化过程
Static{
Try{
Java.sql.DriverManager.registerDriver(new Driver());
}catch(SQL Exception E){
Throw new RuntimeException(“Can’t register driver!”);
}
}
jdbc 批量insert_037 深入JDBC中PreparedStatement对象使用相关推荐
- 2020-08-02 Mysql数据库索引初识、备份、设计原则、JDBC连接、SQL注入、PreparedStatement对象使用、事务处理、连接池
------------------------索引---------------------- 定义:帮助MYSQL高效获取数据的数据结构 ----------主键索引----------prima ...
- mysql jdbc 批量_MYSQL 之 JDBC(十四):批量处理JDBC语句提高处理效率
packagecom.litian.jdbc;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.Sta ...
- java jdbc 批量更新_java – JDBC PreparedStatement,批量更新和生成的密钥
我在批处理中使用jdbc preparedStatement并尝试获取由此创建的生成密钥时出现问题. 代码 : PreparedStatement stmt = null; ... connectio ...
- 批量过滤删除AD中的对象
Get-ADOrganizationalUnit -SearchBase "ou=大生在线失效,dc=51talk,dc=com" -filter * -SearchScope o ...
- JDBC批量插入sql-踩坑笔记
引言 使用JDBC连接mysql进行批量插入数据时出现bug,卡了两天还是没头绪,路过的兄弟如果有什么经验还请指点一番.抱拳抱拳! 控制台提示sql语法有错误: 正文 首先JDBC连接mysql封装了 ...
- JDBC(一)——statement对象、PreparedStatement对象
文章目录 1. 数据库驱动 2. JDBC 3. 第一个JDBC程序 4. statement对象 4.1 简述 4.2 CRUD操作 4.3 代码实现 5. PreparedStatement对象 ...
- Java数据库连接(JDBC)之二:Statement对象和PreparedStatement对象的使用
1,Statement对象是Java 执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句.Statement对象,用于执行不带参数的简单SQL语句. Sta ...
- jdbc 批量执行sql
最近有个需求是需要在java 后端执行导入,数据量比较大, 需要对数据进行很多操作,最后要执行插入数据操作, 一开始先组织好插入数据的sql语句放在数组中,使用的是 jdbcTemplate.batc ...
- jdbc批量调用oracle存储过程,oracle学习笔记(二十三)——JDBC调用存储过程以及批量操作...
jdbc调用存储过程 使用并获得out模式的参数返回值 //存储过程为sum_sal(deptno department.deptno%type,sum in out number) Callable ...
最新文章
- python的Web框架,Django框架中的请求与响应
- Y_CLIENT_QHD_504 role in GM6 ZSAP_CRM_BCR_SALESREP_DAIDE
- css左右布局代码_如何使用CSS位置来布局网站(带有示例代码)
- OCLint+Xcode 代码规范利器
- 由浅到深理解ROS(6)-坐标转换
- 1106: 回文数(函数专题)
- VK维客众筹网整站源码 手机端众筹网站系统源码
- 企业如何进行数据质量评估
- 重庆邮电大学c语言实验报告,重庆邮电大学c语言上机实验期末实验报告.doc
- 笔记本安装黑苹果后无法调节亮度的解决办法 | 小太阳
- Github优秀开源项目
- 绿坝-花季护航 官网论坛
- 2021年微软研究博士奖研金名单出炉!三位华人博士生入选,每人42000美元
- 安卓反编译smali代码注入第三方广告
- 瞎琢磨先生教你优雅的进行参数合法性校验
- [Perl] Data::Dumper模块的用法简介
- 天翼云linux上传工具,(一)天翼云主机安装seafile7.0.3
- 日均5亿查询量,京东到家订单中心的ES架构演进
- 还在吐槽翻译的外版书质量差吗?谈谈我个人的理解
- 深度学习之计算机视觉方向的知识结构
热门文章
- MySQL Connector/C++入门教程(上)
- 系统查找存储过程和触发器
- Multiple substitutions specified in non-positional format; did you mean to add the formatted=false
- python tkinter进度条_在python tkinter中Canvas实现进度条显示的方法
- node升级命令_Vue CLI 4 发布:自动化升级过程,支持自定义包管理器
- python中的ch表示什么_材料符号里面的 CH表示什么意思 : ( )
- 7z001怎么解压在安卓手机上面_安卓zip文件压缩RAR解压手机下载-安卓zip文件压缩RAR解压v1.0最新版下载...
- html 隐藏_HTML实战篇:纯css制作二级横向以及竖向菜单导航
- 计算机名字需要加_PC吗,ecs计算机名字
- 吃货注意接收,精美美食图片壁纸来喽