JDBC——“CRUD”
JDBC
操作和访问数据库
数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
- Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
- PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
- CallableStatement:用于执行 SQL 存储过程
Statement
通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。
我们通过一个示例来看看Statement吧!
演示:
public class StatementTest {@Testpublic void testLogin() {Scanner scan = new Scanner(System.in);System.out.print("用户名:");String userName = scan.nextLine();System.out.print("密 码:");String password = scan.nextLine();// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password+ "'";User user = get(sql, User.class);if (user != null) {System.out.println("登陆成功!");} else {System.out.println("用户名或密码错误!");}}// 使用Statement实现对数据表的查询操作public <T> T get(String sql, Class<T> clazz) {T t = null;Connection conn = null;Statement st = null;ResultSet rs = null;try {// 1.加载配置文件InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);// 2.读取配置信息String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");// 3.加载驱动Class.forName(driverClass);// 4.获取连接conn = DriverManager.getConnection(url, user, password);st = conn.createStatement();rs = st.executeQuery(sql);// 获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();// 获取结果集的列数int columnCount = rsmd.getColumnCount();if (rs.next()) {t = clazz.newInstance();for (int i = 0; i < columnCount; i++) {// //1. 获取列的名称// String columnName = rsmd.getColumnName(i+1);// 1. 获取列的别名String columnName = rsmd.getColumnLabel(i + 1);// 2. 根据列名获取对应数据表中的数据Object columnVal = rs.getObject(columnName);// 3. 将数据表中得到的数据,封装进对象Field field = clazz.getDeclaredField(columnName);field.setAccessible(true);field.set(t, columnVal);}return t;}} catch (Exception e) {e.printStackTrace();} finally {// 关闭资源if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (st != null) {try {st.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}return null;}
}
从上代码可以看见Statement存在拼串的操作,看看输出结果:
小伙伴是不是就有了疑惑,为什么上面都是AA用户,密码不一样,却都能登录成功???
这种现象就是SQL注入,SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。
使用Statement操作数据表存在的弊端
- 问题一:存在拼串操作,繁琐
- 问题二:存在SQL注入问题
如何去解决这两个问题呢,只要用PreparedStatement来取代Statement就可以了。
PreparedStatement
介绍
可以通过调用 Connection 对象的preparedStatement(String sql) 方法获取 PreparedStatement 对象
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值
好处
- 代码的可读性和可维护性。
- PreparedStatement 能最大可能提高性能:
- PreparedStatement 可以防止 SQL 注入
使用PreparedStatement实现增、删、改操作
//通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)public void update(String sql,Object ... args){Connection conn = null;PreparedStatement ps = null;try {//1.获取数据库的连接conn = JDBCUtils.getConnection();//2.获取PreparedStatement的实例 (或:预编译sql语句)ps = conn.prepareStatement(sql);//3.填充占位符for(int i = 0;i < args.length;i++){ps.setObject(i + 1, args[i]);}//4.执行sql语句ps.execute();} catch (Exception e) {e.printStackTrace();}finally{//5.关闭资源JDBCUtils.closeResource(conn, ps);}}
使用PreparedStatement实现查询操作
ResultSet
查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现
ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。
ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。
当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。
- 例如: getInt(1), getString(“name”)
- 注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。
ResultSet 接口的常用方法:
boolean next()
getString()
…
ResultSetMetaData
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
ResultSetMetaData meta = rs.getMetaData();
getColumnName(int column):获取指定列的名称
getColumnLabel(int column):获取指定列的别名
getColumnCount():返回当前 ResultSet 对象中的列数。
getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
isNullable(int column):指示指定列中的值是否可以为 null。
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。
问题1:得到结果集后, 如何知道该结果集中有哪些列 ? 列名是什么?
需要使用一个描述 ResultSet 的对象, 即 ResultSetMetaData
问题2:关于ResultSetMetaData
- 如何获取 ResultSetMetaData: 调用 ResultSet 的 getMetaData() 方法即可
- 获取 ResultSet 中有多少列:调用 ResultSetMetaData 的 getColumnCount() 方法
- 获取 ResultSet 每一列的列的别名是什么:调用 ResultSetMetaData 的getColumnLabel() 方法
资源的释放
- 释放ResultSet, Statement,Connection。
- 数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
- 可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。
代码演示:
// 通用的针对于不同表的查询:返回一个对象 (version 1.0)public <T> T getInstance(Class<T> clazz, String sql, Object... args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {// 1.获取数据库连接conn = JDBCUtils.getConnection();// 2.预编译sql语句,得到PreparedStatement对象ps = conn.prepareStatement(sql);// 3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}// 4.执行executeQuery(),得到结果集:ResultSetrs = ps.executeQuery();// 5.得到结果集的元数据:ResultSetMetaDataResultSetMetaData rsmd = rs.getMetaData();// 6.1通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值int columnCount = rsmd.getColumnCount();if (rs.next()) {T t = clazz.newInstance();for (int i = 0; i < columnCount; i++) {// 遍历每一个列// 获取列值Object columnVal = rs.getObject(i + 1);// 获取列的别名:列的别名,使用类的属性名充当String columnLabel = rsmd.getColumnLabel(i + 1);// 6.2使用反射,给对象的相应属性赋值Field field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t, columnVal);}return t;}} catch (Exception e) {e.printStackTrace();} finally {// 7.关闭资源JDBCUtils.closeResource(conn, ps, rs);}return null;}
上面的获取数据库连接、资源关闭我已经写入了工具类,调用即可:
public class JDBCUtils {public static Connection getConnection() throws Exception {//1.读取配置文件中的4个基本信息InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");//2.加载驱动Class.forName(driverClass);//3.获取连接Connection conn = DriverManager.getConnection(url,user,password);return conn;}public static void closeResource(Connection conn, Statement ps){try {if(ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if (conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}}public static void closeResource(Connection conn, Statement ps,ResultSet rs){try {if(ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if (conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}try {if (rs != null)rs.close();} catch (SQLException e) {e.printStackTrace();}}
}
JDBC——“CRUD”相关推荐
- Spring JDBC和JdbcTemplate CRUD与DataSource示例
Spring JDBC示例和JdbcTemplate CRUD与DataSource示例 Spring JDBC是本教程的主题.数据库是大多数企业应用程序不可或缺的一部分.因此,当谈到Java EE框 ...
- Spring Boot JDBC
JDBC详解 Java Data Base Connectivity,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成.不管是Hi ...
- Spring JDBC 示例
Spring JDBC示例 Spring JDBC是本教程的主题.数据库是大多数企业应用程序不可或缺的一部分.因此,当谈到Java EE框架时,与JDBC的良好集成非常重要. 目录[ 隐藏 ] 1 S ...
- spring jdbc_Spring JDBC示例
spring jdbc Spring JDBC is the topic of this tutorial. Databases are integral part of most of the En ...
- Spring——DAO层、Spring JDBC、Spring事务控制
目录 一.Spring对持久层技术支持 1.Spring支持的持久层技术 2.Spring JDBC 2.1. JDBCTemplate类 2.2.Spring JDBC CRUD操作 2.3.Spr ...
- SpringBoot使用JdbcTemplate案例(学习笔记)
声明:本案例学习http://blog.csdn.net/je_ge,在此感谢je_ge提供的学习用的资料 1.项目结构 2.pom.xml的内容 <project xmlns="ht ...
- JAVAWEB(笔记)
简介 web开发: web,网页的意思,www.baidu.com· 静态web html,sss 提供给所有人看的数据始终不会发生变化! 动态web 淘宝,几乎是所有的网站: 提供给所有人看的数据始 ...
- Apusic Operamasks的资源注入
★ 什么是资源? 开发过程中与业务无关的服务.类的实例或者变量的值.比如:Apusic J2EE应用服务器管理的JDBC服务是资源,用户开发的EJB.WebService是资源.用户定义的配置文件也是 ...
- JavaWeb(狂神老师上课笔记)
JavaWeb Java Web 1.基本概念 1.1.前言 web开发: web,网页的意思 , www.baidu.com 静态web html,css 提供给所有人看的数据始终不会发生变化! 动 ...
最新文章
- zynq tcp如何从网口发数据_ZYNQ_PL与PS的DDR交互
- C++程序运行时内存布局之--无继承情况下的虚函数
- 用户使用说明c语言,(C语言使用指南.docx
- python写xml文件_用python写xml文件
- Spring Boot中使用Spring Security进行安全控制
- mysql 如果存在修改_mysql如存在并发修改可能,一定要注意保证数据一致性
- Python traceback模块的使用(抛异常、报错、输出错误)
- 混沌思维模型实战课:如何发现击穿破局点的单一要素?
- 腾讯基于预训练模型的文本内容理解实践
- SAMBA用户访问指定的目录
- 关于CUDA中cutil的一些问题
- python编程的区别_Python与其它编程语言的区别
- vue 实现12个月的平铺式日历插件
- “3W1H法”浅析三层架构
- 刚刚用鸿蒙跑了个“hello world”!跑通后,我特么开始怀疑人生了....
- 大数据背景下互联网用户行为分析
- 国内新锐买手品牌BSiEE 本涩启动第三届品牌代言人招募活动
- 船舶物资与市场杂志船舶物资与市场杂志社船舶物资与市场编辑部2022年第7期目录
- WinSock控件及WinSockAPI
- 国产半导体设备多年沉淀终爆发!2020制程、测试、硅片设备全面开花