300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > JDBC连接mysql 创建表 操作数据 PreparedStatement防注入 sql语句返回值类型知识汇总

JDBC连接mysql 创建表 操作数据 PreparedStatement防注入 sql语句返回值类型知识汇总

时间:2019-07-16 05:13:24

相关推荐

JDBC连接mysql 创建表 操作数据 PreparedStatement防注入 sql语句返回值类型知识汇总

JDBC连接过程:

import java.sql.*;/*** Description:* Created by CWG on /10/29 21:05*/public class ConnectionTest {public static void main(String[] args){String user = "root";String password = "cheng";String url = "jdbc:mysql://localhost:3306/mysql?serverTimezone=UTC";String driver = "com.mysql.cj.jdbc.Driver";Connection conn = null;Statement stm = null;try{Class.forName(driver); //1.将mysql驱动注册到DriverManager中去conn = DriverManager.getConnection(url,user,password); //2. 建立连接stm = conn.createStatement(); // 3. 创建一个Statement 实例用于发送sql语句stm.execute("sql语句") //4.执行sql语句} catch (Exception e) {e.printStackTrace();}}}

大概流程是这样:

首先第一步装载驱动,个人理解就是:从DriverManager名字来看,该对象是来做sql语句跟数据库数据交互的一个中间者,其功能实现还是靠com.mysql.cj.jdbc.Driver类完成。

从源码看出,其继承NonRegisteringDriver类并实现java.sql.Driver接口,可以自查源码发现com.mysql.cj.jdbc.Driver类功能都是继承自NonRegisteringDriver类。JDBC规范要求Driver类(com.mysql.cj.jdbc)在使用前必须向DriverManger注册自己。注册过程在Driver类的静态代码块中实现。也就是说只要类被加载,就完成了向驱动管理器的注册。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}}

接着就是建立连接以及通过conn.createStatement()创建一个Statement实例,用来传递sql语句。然后执行sql语句,步骤3-4有几点需要注意:

(1)步骤3中,除了conn.createStatement()创建Statement实例,还可以通过conn.prepareStatement来创建PreparedStatement实例。

(2)步骤4中,stm.execute是一个通用执行sql语句方法,除此之外还有executeQueryexecuteUpdate方法。

具体区别后边讲。


JDBC创建表:

stm.execute("create table users(" +"id int AUTO_INCREMENT," +"name VARCHAR(20), " +"age int," +"sex char(2)," +"PRIMARY KEY (id));");

根据上边连接好的数据库,执行以上语句来创建一个users用户表,其语句格式跟mysql完全一样,只是写成了字符串。另外注意AUTO_INCREMENT自增约束只能用于主键。


JDBC操作数据:

插入数据

stm.execute("INSERT into users(name,age,sex) VALUES ('小王',23,'男')");stm.execute("INSERT into users(name,age,sex) VALUES ('小猪',16,'女')");stm.execute("INSERT into users(name,age,sex) VALUES ('小李',18,'男')");stm.execute("INSERT into users(name,age,sex) VALUES ('小菜',23,'女')");//批量操作方式String sql0 = "INSERT into users(name,age,sex) VALUES ('小王',23,'男')";String sql1 = "INSERT into users(name,age,sex) VALUES ('小猪',16,'女')";String sql2 = "INSERT into users(name,age,sex) VALUES ('小李',18,'男')";String sql3 = "INSERT into users(name,age,sex) VALUES ('小菜',23,'女')";stm.addBatch(sql0);stm.addBatch(sql1);stm.addBatch(sql2);stm.addBatch(sql3);stm.executeBatch();

查询数据

stm.execute("SELECT * from users where sex = '男'");

问题来了:插入数据没问题,然而查询数据虽然也正常执行,但是却没返回要查询的数据。另外这里的sql语句只能是静态的,若想在sql语句中传入参数,如何处理?这里就是上边提到的那两点。下边具体说明。


Statement和 PreparedStatement:

从功能上来讲,PreparedStatement可以通过参数传递方式来执行sql语句,参数位置用占位符表示。而Statement没有这样的机制,只能写实际的字符串sql语句。

stm = conn.createStatement();String name = "小白";String age = "17";String sex = "男";String sql = "insert into users(name,age,sex) values('"+ name + "',"+ age +",'"+ sex +"')";stm.execute(sql);

Statement方式传递参数,只能通过字符串拼串来实现,整体还是一个字符串语句。另外注意拼串时,属性name、sex这些字符串属性的单引号不可省略。

PreparedStatement ps = null;try{Class.forName(driver);conn = DriverManager.getConnection(url,user,password);String sql = "insert into users(name,age,sex) values(?,?,?)";ps = conn.prepareStatement(sql);ps.setString(1,"小灰");ps.setInt(2,21);ps.setString(3,"女");ps.execute();} catch (Exception e) {e.printStackTrace();}

到这里表中数据(id不连续主要自己删了一行,这里不要在意)

PreparedStatement方式实现sql语句执行,sql语句中先通过来占位,然后通过setXX方法来拼串,方法中第一个参数代表第几个参数。

两种方式区别: 效率问题:Statement每次执行sql语句,相关数据库都要执行sql语句的编译;PreparedStatement是预编译的(插入的参数不再编译), 采用Cache机制(预编译语句,放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,对于批量处理可以大大提高效率。PrepareStatement中执行的SQL语句中是可以带参数的,也就是说可以替换变量,尽量采用使用?号的方式传递参数,增加代码的可读性又可以预编译加速;而Statement则不可以。防止SQL注入:在SQL中包含特殊字符或SQL的关键字时,Statement将出现不可预料的结果,可用PreparedStatement来解决,因为插入的参数不会再进行编译,比较安全。

以上3点摘自:/gbb123/p/7053772.html


SQL注入问题:

比如有这样一个情况:

String table = user; delete user;-- ; // 表名为 user; delete user;--String name = "admin";有如下select语句String sql = "select * from " + table + "where name = '" + name +"'";

Statement进行sql语句解析为:select * from user; delete user; -- where name = 'admin';,–后面的语句被注释,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,如果存在user用户表,则信息全被删了。

而PreparedStatement会将传入的参数全当作字符串来处理,不会对传入参数进行编译,因此可以避免该问题。虽然这里用一个恶意表名来举例,场景感不是很强,但是换一种场景,在系统登录界面,通过用户名来搞恶意注入,那问题就大了。


executeQuery、executeUpdate 和 execute:

前边有一个问题就是返回值问题,execute虽然是全能sql语句操作,可以执行任何sql语句,但其返回值类型却是boolean型,select语句执行时,如何得到查询结果?

实际上,Statement和PreparedStatement接口都提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。

executeQuery 用于产生单个结果集(ResultSet,不是单行数据)的语句。executeUpdate 用于执行 INSERT、UPDATE 或 DELETE 语句,SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数(int),指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。execute 可用于执行任何SQL语句,返回一个boolean值,表明执行该SQL语句是否返回了ResultSet。如果执行后第一个结果是ResultSet,则返回true,否则返回false。但它执行SQL语句时比较麻烦,通常我们没有必要使用execute方法来执行SQL语句,而是使用executeQuery或executeUpdate更适合,但如果在不清楚SQL语句的类型时则只能使用execute方法来执行该SQL语句了。

以上三者区别摘自:/yunqingtuo/p/10512677.html


execute实例:

stm = conn.createStatement();boolean res0 = stm.execute("INSERT into users(name,age,sex) VALUES ('小C',25,'女')");boolean res1 = stm.execute("SELECT * from users where sex = '男'");System.out.println(res0 + "====" + res1);

返回false====true,看出execute会在select语句中返回true,表明产生ResultSet结果集,而insert语句返回false

获取execute的结果集:

stm = conn.createStatement();boolean res1 = stm.execute("SELECT name,age from users where sex = '男'");ResultSet resultSet = stm.getResultSet(); //注意通过Statement实例stm获取结果集// ResultSetMetaData meta = resultSet.getMetaData(); //获取每一条元数据信息// int columnCount = meta.getColumnCount(); //统计一条元数据有几个字段while (resultSet.next()){System.out.println("name:" + resultSet.getString("name") + ", age:" + resultSet.getInt("age"));}


executeQuery实例:

ResultSet resultSet = stm.executeQuery("SELECT name,age from users where sex = '男'");while (resultSet.next()){System.out.println("name:" + resultSet.getString("name") + ", age:" + resultSet.getInt("age"));}

executeQuery返回值就是ResultSet,不必像execute通过stm.getResultSet()来获取结果集。


executeUpdate 实例:

int res = stm.executeUpdate("delete from users where sex = '男'");System.out.println("语句executeUpdate执行后受影响的行数为:" + res);

结果:语句executeUpdate执行后受影响的行数为:3,另外executeUpdate不可以执行select操作


本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。