B029-JDBC增强

news2024/11/24 16:30:47

目录

      • PreparedStatement 查询
        • 1.sql注入
        • 2.Statement分析 (面试题)
        • 3.PreparedStatement (面试题)
      • 登录功能的完善
      • 事务
      • 链接池
        • 概念
        • 实现
          • DBCP连接池实现
            • 第一种配置方式
            • 第二种配置方式
      • 返回主键
      • BaseDao的抽取

PreparedStatement 查询

1.sql注入

就是在sql的字符串拼接的时候,加入了特定的条件判断,

如:SELECT * FROM student where name=’ 小坤坤255255 ’ OR 1=1

代码

public class StudentDaoImpl  implements IStudentDao{
	//Statement的写法
	@Override
	public Student login(String name, String Password) {
		//通过工具类获取连接
		Connection conn = JDBCUtil.Instance().getconn();
		Statement State =null;
		ResultSet rs=null;
		Student student = new Student();
		try {
			 State = conn.createStatement();
			  rs = State.executeQuery("select * from student where name='"+name+"'and password ='"+Password+"'");
		      while (rs.next()) {
		    	  student.setId(rs.getInt("id"));
		    	  student.setName(rs.getString("name"));
		    	  student.setPassword(rs.getString("password"));
			} 
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.Instance().close(rs, State, conn);
		}
		return student;
	}
}
public class JDBCTest {
	@Test
	public void testName() throws Exception {
		StudentDaoImpl studentDaoImpl = new  StudentDaoImpl();
		//正常的代码
//		Student stu = studentDaoImpl.login("网通", "123");
		//sql注入的代码
		Student stu = studentDaoImpl.login("网通", "123' or '1=1");
		System.out.println(stu);
		if(stu.getName()!=null){
			System.out.println("账号存在登录成功");
		}else{
			System.out.println("账号不存在  ..登录失败");
		}
	}
}
2.Statement分析 (面试题)

1.通过上面sql注入的案例我们发现 Statement 它可能会导致sql注入的问题
2.通过这几天的sql的书写我发现 Statement 拼接sql相当复杂,稍微有一点点差错就会导致sql语句有问题

解决方法:PreparedStatement

3.PreparedStatement (面试题)

PreparedStatement 很好的解决了Statement的问题
1.不用担心注入问题(双引号之内看成一个整体的字符串而不是两个字符串和一个关键字),
2.sql语句不用复杂拼接,
3.会预处理sql语句,执行速度也更快

代码:
StudentDaoImpl

	//PreparedStatement写法
	@Override
	public Student login(String name, String Password) {
		 Connection conn = JDBCUtil2.Instance().getconn();
		 PreparedStatement ps=null;
		 ResultSet rs =null;
		 Student student = new Student();
		 try {
			 ps= conn.prepareStatement("select * from student  where name=? and password=?");
			 ps.setString(1, name);
			 ps.setString(2, Password);
			 rs = ps.executeQuery();
			 while(rs.next()){
				 student.setId(rs.getInt("id"));
				 student.setName(rs.getString("name"));
				 student.setPassword(rs.getString("password"));
			 }
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil2.Instance().close(rs, ps, conn);
		}
	return student;
	}

JDBCTest

	@Test
	public void testName() throws Exception {
		StudentDaoImpl studentDaoImpl = new  StudentDaoImpl();
		//正常的代码
//		Student stu = studentDaoImpl.login("网通", "123");
		//sql注入的代码
		Student stu = studentDaoImpl.login("网通", "123' or '1=1");
		System.out.println(stu);
		if(stu.getName()!=null){
			System.out.println("账号存在登录成功");
		}else{
			System.out.println("账号不存在  ..登录失败");
		}
	}

问题:PreparedStatement和Statement 不是同一个类为什么关资源的时候可以传PreparedStatement
因为 PreparedStatement 继承了 Statement,(多态)

PreparedStatement :

  // 预处理 这时候就会把sql发送到数据库了,只是这时还不会执行sql
  select * from student  where name=? and password=? 		//变量位置使用?先占住,(这时已经发了sql语句了)
  ps= conn.prepareStatement("select * from student  where name=? and password=?");
  // 把?替换成对应的值
  ps.setString(1, name);
  ps.setString(2, Password);
  // 执行sql  这时的执行就是一个执行命令,不会发sql语句(前面已发)
  rs = ps.executeQuery();

Statement:

  //创建 Statement 对象 
  State = conn.createStatement();
  // 发送并执行sql 
  rs = State.executeQuery("select * from student where name='"+name+"'and password ='"+Password+"'");

PreparedStatement 是 Statement 子类,速度比Statement 快,能避免sql 注入,可以不用拼接sql语句

登录功能的完善

StudentDaoImpl

	@Override
	public Student QueryByUsername(String name) {
		Connection conn = JDBCUtil2.Instance().getconn();
		PreparedStatement ps = null;
		ResultSet rs = null;
		Student student = new Student();
		try {
			ps = conn.prepareStatement("select * from student where name=?");
			ps.setString(1, name);
			rs = ps.executeQuery();
			while (rs.next()) {
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setPassword(rs.getString("password"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil2.Instance().close(rs, ps, conn);
		}
		return student;
	}

JDBCTest

	// 登录的第二种实现方式
	@Test
	public void login() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		// 查询是小坤坤(用户名)的信息,这个用户名 应该是前台(浏览器) 用户 传过来的 -- 模拟
		Student student = studentDaoImpl.QueryByUsername("小坤坤");
		// 判断用户名是否存在
		if (student.getName() == null) {
			System.out.println("账号不存在");
		}
		// else 就是账号存在
		else {
			// 判断这个账号的密码是否正确 (这个密码应该是前台(浏览器) 用户 传过来的)
			if (!"8848".equals(student.getPassword())) {
				System.err.println("密码错误");
			} else {
				System.out.println("登录成功");
			}
		}
	}

事务

	@Test
	public void Testtrans() throws Exception {
		Connection connection = null;
		PreparedStatement ps = null;
		PreparedStatement ps2 = null;
		try {
			connection = JDBCUtil2.Instance().getconn();
			// 不提交事务 (sql执行了,改变了数据库的数据,但是后面没有写提交事务数据库就不能有变化),
			connection.setAutoCommit(false);
			String sql = "update bank set money=money-1000 where name='过儿'";
			ps = connection.prepareStatement(sql);
			ps.execute();
			// 在这个位置 出现异常
			int a=0/0;
			String sql2 = "update bank set money=money+1000 where name='姑姑'";
			ps2 = connection.prepareStatement(sql2);
			ps2.execute();
			// 提交事物 (数据库可以发生变化了)
			connection.commit();
		} catch (Exception e) {
			// 回滚 (你数据库改变了之后我还是可以回滚)
			/*当我们把自动提交关闭,那sql就不是提交执行,于是我们一定要记住,当我们一个整体功能完成之后,自己要手动进行提交;
			--conn.commit但是失败之后,要记住数据回滚*/
			connection.rollback();
		} finally {
			ps2.close();
			ps.close();
			connection.close();
		}
	}

ACID (面试)
事务 : 一组操作 要么都成功 要么都失败
事务具有4个特征,分别是原子性、一致性、隔离性和持久性,简称事务的ACID特性;
原子性(atomicity) :一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作
一致性(consistency) : 一个事务执行前后,数据库都处于一致性状态
隔离性(isolation): 每一个事务都是单独的,事务和事务之间不影响
持久性(durability): 事务执行完了, 持久化到数据库

链接池

概念

在这里插入图片描述
你创建了一个池塘 池塘里面你放了很多链接 用完了就放回去 -->节省开关链接的时间

实现

在Java中,连接池使用javax.sql.DataSource接口来表示连接池,这里的DataSource就是连接池,连接池就是DataSource。
DataSource是接口,和JDBC一样,是Sun公司开发的一套接口,需要各大厂商实现;
需要导入相应包—导包…
所以使用连接池,首先需要导包;

常用的DataSource的实现有下面两种方式:
DBCP: Spring推荐的(Spring框架已经集成DBCP)
C3P0: Hibernate推荐的(早期)(Hibernate框架已经集成C3P0)持久层

DBCP连接池实现

1.导入jar包
commons-dbcp-1.3.jar,commons-pool-1.5.6.jar

2.代码
BasicDataSource就是DBCP的连接池实现

第一种配置方式
public class JDBCUtil {
	// 构造方法私有化
	private JDBCUtil() {
	};

	private static JDBCUtil instance;
	// 一启动就加载驱动 只执行一次
	static Properties ps = null;
	static BasicDataSource ds = null;
	static {
		ps = new Properties();
		try {
			ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
			ds = new BasicDataSource();
			ds.setDriverClassName(ps.getProperty("dirverClassName"));
			ds.setUsername(ps.getProperty("username"));
			ds.setPassword(ps.getProperty("password"));
			ds.setUrl(ps.getProperty("url"));
		} catch (IOException e) {
			e.printStackTrace();
		}

/*		 try {
		 		ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
		 		Class.forName(ps.getProperty("dirverClassName"));
		 } catch (Exception e) {
		 		e.printStackTrace();
		 }*/

		instance = new JDBCUtil();
	}

	public static JDBCUtil Instance() {
		return instance;
	}

	// 写加载数据库的驱动
	public Connection getconn() {
		Connection connection = null;
		try {
			//换成新的获取连接池的方式
			connection = ds.getConnection();
			// connection = DriverManager.getConnection(ps.getProperty("url"),
			// ps.getProperty("username"), ps.getProperty("password"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connection;
	}

	// 关闭资源
	public void close(ResultSet rs, Statement State, Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (State != null) {
					State.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null) {
						conn.close();
					}
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
public class test {
	public static void main(String[] args) {
		Connection connection = JDBCUtil.Instance().getconn();
		try {
			String sql = "update bank set money=money-500 where name='过儿'";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
第二种配置方式
public class JDBCUtil2 {
	// 构造方法私有化
	private JDBCUtil2() {
	};

	private static JDBCUtil2 instance;
	// 一启动就加载驱动 只执行一次
	static Properties ps = null;
	static DataSource ds = null;
	static {
		ps = new Properties();
		try {
			ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
			// 创建连接池
			ds = BasicDataSourceFactory.createDataSource(ps);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// try {
		// 		ps.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
		// 		Class.forName(ps.getProperty("dirverClassName"));
		// } catch (Exception e) {
		// 		e.printStackTrace();
		// }

		instance = new JDBCUtil2();
	}

	public static JDBCUtil2 Instance() {
		return instance;
	}

	// 写加载数据库的驱动
	public Connection getconn() {
		Connection connection = null;
		try {
			//换成新的获取连接池的方式
			connection = ds.getConnection();
			// connection = DriverManager.getConnection(ps.getProperty("url"),
			// ps.getProperty("username"), ps.getProperty("password"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connection;
	}

	// 关闭资源
	public void close(ResultSet rs, Statement State, Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (State != null) {
					State.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null) {
						conn.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
public class test {
	public static void main(String[] args) {
		Connection connection = JDBCUtil2.Instance().getconn();
		try {
			String sql = "update bank set money=money-500 where name='过儿'";
			PreparedStatement ps = connection.prepareStatement(sql);
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

返回主键

场景举例:先后添加product和product_stock时,需要拿到product插入时自增的id存到product_stock的product_id里

看文档做

StudentDaoImpl

	@Override
	public void insert(Student stu) {
		Connection conn = JDBCUtil.Instance().getconn();
		PreparedStatement ps = null;
		try {
			String sql = "insert into student(name,password) values(?,?)";
			ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			ps.setString(1, stu.getName());
			ps.setString(2, stu.getPassword());
			ps.executeUpdate();
			ResultSet rs = ps.getGeneratedKeys();
			while (rs.next()) {
				System.err.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

JDBCTest

	@Test
	public void addStudent() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		Student stu = new Student();
		stu.setName("小波波");
		stu.setPassword("857857958958");
		studentDaoImpl.insert(stu);
	}

BaseDao的抽取

BaseDao

public class BaseDao {
	public void excuteUpdate(String sql, Object... objects) {
		Connection conn = JDBCUtil2.Instance().getconn();
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < objects.length; i++) {
				ps.setObject(i + 1, objects[i]);
			}
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtil2.Instance().close(null, ps, conn);
		}
	}
}

实现类:

public class StudentDaoImpl extends BaseDao  implements IStudentDao{
    
    @Override
	public void insert(Student stu) {
		String  sql="insert into student(name,password) values(?,?)";
		excuteUpdate(sql, stu.getName(),stu.getPassword());
	}
	@Override
	public void update(Student stu) {
		String sql = "update student set name=?,password=? where id =?";
		excuteUpdate(sql, stu.getName(),stu.getPassword(),stu.getId());
	}
	@Override
	public void delete(Student stu) {
		String sql = "delete from student where id = ?";
		excuteUpdate(sql, stu.getId());
	}
}

JDBCTest

	@Test
	public void addStudent() throws Exception {
		StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
		Student stu = new Student();
		stu.setName("小波波");
		stu.setPassword("857857");
		stu.setId(254172);
//		studentDaoImpl.insert(stu);
//		studentDaoImpl.delete(stu);
		studentDaoImpl.update(stu);
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1304275.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChibiOS简介3/5

ChibiOS简介3/5 1. 源由2. ChibiOS基础知识3/52.7 Chapter 7 - RT Time and Intervals2.7.1 Basic concepts2.7.2 APIs 2.8 Chapter 8 - RT Virtual Timers2.8.1 Basic concepts2.8.2 Tickless Mode2.8.3 APIs 2.9 Chapter 9 - RT Scheduler2.9.1 Basic concepts2.9.2 System C…

两线制无源 4-20mA 回路供电隔离变送器

两线制无源 4-20mA 回路供电隔离变送器 一入一出两线制无源 4-20mA 回路供电隔离变送器 概述&#xff1a;JSD TAW-1001D-100L-F 系列隔离变送器是 4-20mA 两线制回路供电的电流隔离变送配电器,该隔离变送器采用电磁隔离技术,并通过输入端馈电方式,给输入端两线制仪器仪表设备供…

数据库 02-03补充 聚合函数--一般聚合分组和having

聚合函数&#xff1a; 01.一般的聚合函数&#xff1a; 举个例子&#xff1a; 一般聚合函数是用于单个元祖&#xff0c;就是返回一个数值。 02.分组聚合&#xff1a;可以返回多个元祖 举个例子&#xff1a; 分组的注意&#xff1a; 主要的是根据分组的话&#xff0c;一个…

【git push ERROR: commit id: missing Change-Id in message footer】

使用 gerrit 后&#xff0c;提交代码会出现如下截图问题&#xff1a; 临时解决&#xff1a; step1: 把上面红色的那条gitidir复制下来执行下&#xff1a; step2:执行下面的命令会添加change_id git commit --amendstep3: 然后推送代码到服务器上 git push origin HEAD:refs/fo…

万界星空科技电子装配行业MES解决方案

电子电器装配属于劳动密集型、科技含量较高的行业&#xff0c;产品零部件种类繁多&#xff0c;生产组装困难&#xff0c;生产过程存在盲点&#xff0c;同时也决定了生产流水线多且对自动化水平要求较高。 万界星空科技提供的电子行业MES解决方案&#xff0c;提供从仓储管理、生…

排序算法:【选择排序]

一、选择排序——时间复杂度 定义&#xff1a;第一趟排序&#xff0c;从整个序列中找到最小的数&#xff0c;把它放到序列的第一个位置上&#xff0c;第二趟排序&#xff0c;再从无序区找到最小的数&#xff0c;把它放到序列的第二个位置上&#xff0c;以此类推。 也就是说&am…

STM32 CAN多节点组网项目实操 挖坑与填坑记录

摘要 CAN线性组网项目开发过程中遇到的数据丢包问题&#xff0c;并尝试解决的记录和推测分析。 关键词 CAN串联多节点通讯、CAN10节点通讯、CAN数据丢包、STM32 CAN 背景/项目介绍 概述&#xff1a; 开发了一个多节点线性组网采集数据的项目。 系统包含1个供电和数据网关板还有…

如何利用Guava优化Java网络编程

第1章&#xff1a;引言 大家好&#xff01;今天小黑要和咱们聊聊一个很酷的话题&#xff1a;如何利用Google的Guava库来优化Java网络编程。网络编程&#xff0c;这玩意儿听起来就高大上&#xff0c;不是吗&#xff1f;但实际上&#xff0c;它充满了各种挑战。从处理复杂的数据…

【二分查找】【滑动窗口】LeeCode2528:最大化城市的最小电量

作者推荐 【动态规划】【广度优先】LeetCode2258:逃离火灾 本文涉及的基础知识点 二分查找算法合集 滑动窗口 题目 给你一个下标从 0 开始长度为 n 的整数数组 stations &#xff0c;其中 stations[i] 表示第 i 座城市的供电站数目。 每个供电站可以在一定 范围 内给所有城…

OpenHarmony创新赛人气投票活动,最佳人气作品由你来定!

12月1日至12月15日 十大入围作品线上投票激战正酣 最佳人气作品&#xff0c;由你来定&#xff01; 投票链接&#xff1a;OpenHarmony创新赛人气作品投票正式开启——最佳人气作品&#xff0c;由你来定&#xff01; - 文章 OpenHarmony开发者论坛

uniCloud(一) 新建项目、初始化服务空间、云对象访问测试

一、新建一个带有unicloud 二、创建一个服务空间 1. 右键uniCloud&#xff0c;关联云服务空间 我当前没有服务空间&#xff0c;需要新建一个服务空间&#xff0c;之后将其关联。初始化服务空间需要的时间有点长 服务空间初始化成功后&#xff0c;刷新HBuilder&#xff0c;勾选…

vue3使用Mars3D写区块地图

效果图 引入相关文件 因为我也是第一次使用&#xff0c;所以我是把插件和源文件都引入了&#xff0c;能使用启动 源文件 下载地址&#xff1a; http://mars3d.cn/download.html 放入位置 在index.html中引入 <!--引入cesium基础lib--><link href"/static/C…

互联网加竞赛 opencv 图像识别 指纹识别 - python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器视觉的指纹识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适…

【Docker】从零开始:18.使用Dockerfile构造自己的KingbaseES数据库镜像

【Docker】从零开始&#xff1a;17.使用Dockerfile构造自己的数据库镜像 新建一个自定义目录并创建Dockerfile文件上传需要的文件到自定义目录下注意docker-circle-init.sh文件内容password 内容 开始打包注意打包完成后执行 尝试用工具连接数据库 kingbase.tar.gz 包过大我就上…

阻抗控制实现更快更精准(跟踪精度,较小且稳定的接触力)

阻抗控制是一种模拟人类肌肉阻抗特性的控制方法&#xff0c;可以实现更快更精准的机器人运动控制&#xff0c;同时具有较小的接触力和稳定的跟踪精度。 Kd 10; Bd 5 ; Md 2; 1e5/(0.0005*s^25*s1) 5e4/(0.1*s^21*s1) 1e4/(0.1*s^21*s1) 增益较小时容易跟踪性能不足&#xf…

机房末端配电中机柜PDU是如何工作的?

鉴于IDC数据中心7*24小时的运营要求以及对电源效率的日益关注&#xff0c;机柜PDU&#xff08;Power Distribution Unit&#xff0c;电源分配单元&#xff09;已成为数据中心基础设施的重要组成部分。在很多初次接触机柜PDU的人看来&#xff0c;其作用看上去类似于简单的插线板…

用心研发好产品:健康品牌podeey是如何做到的?

在分析消费者健康需求的同时&#xff0c;美国podeey能量生命有限公司&#xff08;PODEEY Biotechnology LLC.&#xff09;不断提升自主研发实力&#xff0c;并且一直注重汇集全球前沿的研发力量&#xff0c;与贵州宏臻菌业达成战略合作&#xff0c;始终致力于以科学技术为核心&…

微信小程序js数组对象根据某个字段排序

一、排序栗子 注: 属性字段需要进行转换,如String类型或者Number类型 //升序排序 首元素(element1)在前 降序则(element1)元素在后 data data.sort((element1, element2) >element1.属性 - element2.属性 ); 二、代码 Page({/*** 页面的初始数据*/data: {user:…

Axure RP 9 入门教程

1. Axure简介 Axure 是一个交互式原型设计工具&#xff0c;可以帮助用户创建复杂的交互式应用程序和网站。Axure 能够让用户快速构建出具有高度可交互性的原型&#xff0c;可以在团队中进行协作、分享和测试。 使用 Axure 可以设计出各种不同类型的原型&#xff0c;包括网站、移…

windows下安装git中文版客户端

下载git Windows客户端 git客户端下载地址&#xff1a;Git - Downloads 我这里下载的是Git-2.14.0-64-bit.exe版本 下载TortoiseGit TortoiseGit客户端下载地址&#xff1a;Download – TortoiseGit – Windows Shell Interface to Git TortoiseGit客户端要下载两个&#…