JDBC
JDBC介绍
Sun公司为了简化开发人员的(对数据库的统一)操作,提供了(Java操作数据库的)规范,俗称JDBC,这些规范的由具体由具体的厂商去做
对于开发人员来说,我们只需要掌握JDBC接口的操作即可
所需要的jar包
- java.sql(默认有)
- javax.sql(默认有)
还需要导入数据库驱动包
java程序链接mySQL
注意! 增删改操作都需要提交事务
步骤:
- 加载驱动
- 登陆链接数据库对象
- 创建statement对象,用于执行sql语句 statement(清单)
- 执行sql语句
- 返回结果集,结果集中封装了我们查询的所有结果
- 释放链接
// 1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //协议://主机:端口/数据库名?编码设置&使用安全的链接 String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true"; String use = "root"; //用户名 String password = "123456"; //密码 //2.登陆链接数据库对象 Connection connection = DriverManager.getConnection(url, use, password); //3.创建statement对象,用于执行sql语句 statement(清单) Statement statement = connection.createStatement(); //4.执行sql语句 String sql = "SELECT * from class"; //sql语句 //5.返回结果集,结果集中封装了我们查询的所有结果 ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ System.out.println("classno:"+resultSet.getNString("classno")); System.out.println("classname:"+resultSet.getNString("classname")); System.out.println("department:"+resultSet.getNString("department")); System.out.println("monitor(班长):"+resultSet.getNString("monitor(班长)")); System.out.println("=========================================================="); } //6.释放链接 resultSet.close(); statement.close(); connection.close(); } }
几个重要对象
DirverManager 驱动管理
Class.forName("com.mysql.jdbc.Driver"); DriverManager.registerDriver(new Driver()); //这是Driver源码
URL 资源地址
//协议://主机:端口/数据库名?时区设置&编码设置&使用安全的链接 String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true";
Connection 链接对象,操作数据库的对象
connection.commit(); //提交事务 connection.rollback(); //回滚事务 connection.setAutoCommit(); //自动提交事务 /* Statemen 清单,执行sql的对象 */ ```java statement.executeQuery("sql"); //执行查询,返回结果集 statement.executeUpdate("sql"); //执行更新(插入和删除也算更新),返回受影响的行数 statement.execute("sql"); //执行全部的sql语句
ResultSet:查询后的结果集
获取数据:
resultSet.getNString(); resultSet.getObject(); //不知道什么类型的情况下使用 resultSet.getInt(); resultSet.getDate(); resultSet.getFloat();
指针移动:
resultSet.next(); resultSet.previous(); resultSet.absolute(); resultSet.beforeFirst(); resultSet.afterLast();
关闭链接
resultSet.close(); statement.close(); connection.close();
SQL注入的问题
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
即:通过sql语句的漏洞来实现一些非法操作.
// 欲根据用户id来进行获取用户的其他信息,但是使用如下语句就会将所有用户的信息都查询到 select * from db01.user where (id =' 'or 1=1)"; --sql注入
PreparedStatement对象
可以防止sql注入,并且效率更高,如: 在编辑sql语句时使用?代表占位符,并且预编译sql语句,随后在设置参数防止sql注入
常用方法:
preparedStatement.executeQuery(); preparedStatement.executeUpdate(); preparedStatement.setString(); //给参数传递字符串类型的值 preparedStatement.setInt(); //给参数传递 int 类型的值 preparedStatement.setDate(); //给参数传递 Date 类型的值 ... 等等
例子:
//带参数的sql语句 String sql = "select * from db01.user where(id = ?)" ; //预编译sql语句并且返回一个PreparedStatement对象 preparedStatement = con.prepareStatement(sql); //给参数传递值(适当的使用对应类型的方法能提高效率) preparedStatement.setString(1,id); //注意下标从1开始 //运行sql语句 resultSet = preparedStatement.executeQuery();
解藕,封装工具类
我们可以将配置信息编写成配置文件(xxx.properties),然后通过 Properties
类读取文件内容对应参数来配置信息
配置文件db.properties, 我们需要将此配置文件放入字节码的相同路径(maven项目的resources目录下)
# 驱动类名 driver=com.mysql.cj.jdbc.Driver # //协议://主机:端口/数据库名?设置时区&编码设置&使用安全的链接协议 url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true user=root password=123456
JdbcUtil类
package SQL_injection; import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JdbcUtility { // 初始化变量,并且避免作用域问题 static Properties properties = new Properties(); static Connection con = null; static PreparedStatement preparedStatement = null; static ResultSet resultSet = null; static String username = null; static String password = null; //初始化配置 static { // 获取输入流, 通过此类的类加载器获取类加载路径,进而获取到配置文件的输入流 InputStream in = JdbcUtility.class.getClassLoader().getResourceAsStream("db.properties"); try { // 通过properties对象加载配置文件的输入流 properties.load(in); //相当于加载驱动Class.forName("com.mysql.jdbc.Driver"); 只不过是将配置文件的driver参数获取出来 JdbcUtility.class.forName(properties.getProperty("driver")); } catch (Exception e) { e.printStackTrace(); } } //使用配置文件内容信息链接数据库 public JdbcUtility(){ try { //获取配置文件信息 String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password"); // 根据参数链接数据库 con = DriverManager.getConnection(url,user,password); } catch (SQLException throwables) { throwables.printStackTrace(); } } //使用自定义的用户名和密码登陆数据库 public JdbcUtility(String username,String password){ try { con = DriverManager.getConnection(properties.getProperty("url"), username, password); } catch (SQLException throwables) { throwables.printStackTrace(); } } public boolean select(String id){ String sql = "select * from db01.user where(id = ?)" ; //执行查询语句 try { preparedStatement = con.prepareStatement(sql); preparedStatement.setString(1,id); resultSet = preparedStatement.executeQuery(); if(!resultSet.next()) { System.out.println("查询失败!"); return false; } } catch (SQLException throwables) { throwables.printStackTrace(); } return true; } public void getResult(){ try { do { System.out.print("id:"+resultSet.getString(1)+"\t"); //System.out.println("password:"+resultSet.getString(0)+"\t"); System.out.print("name:"+resultSet.getString(3)+"\t"); System.out.print("sex:"+resultSet.getString(4)+"\t"); System.out.print("birthday:"+resultSet.getString(5)+"\t"); System.out.println(); } while (resultSet.next()); } catch (Exception e){ e.printStackTrace(); } } public void insert(String id ,String name,String sex ){ String sql = "insert into db01.user (id,name,sex,birthday) " + "values(?,?,?,?)" ; try { preparedStatement = con.prepareStatement(sql); preparedStatement.setString(1,id); preparedStatement.setString(2,name); preparedStatement.setString(3,sex); Date date = new Date(new java.util.Date().getTime()); preparedStatement.setDate(4,date); int n = preparedStatement.executeUpdate(); if (n == 0) System.out.println("插入失败!"); } catch (SQLException throwables) { throwables.printStackTrace(); } } //删除 public void delete(String id){ String sql = "delete from db01.user where(id = ?);" ; try { preparedStatement = con.prepareStatement(sql); preparedStatement.setString(1,id); if (preparedStatement.executeUpdate()==0) System.out.println("删除失败!"); } catch (SQLException throwables) { throwables.printStackTrace(); } } public void update(String id,String columnname,String value){ String sql = "update db01.user set "+columnname +" = ? where (id = ? )" ; try { preparedStatement = con.prepareStatement(sql); //preparedStatement.setString(1,columnname); preparedStatement.setString(1,value); preparedStatement.setString(2,id); if(preparedStatement.executeUpdate()==0) System.out.println("更新失败"); } catch (SQLException throwables) { throwables.printStackTrace(); } } //关闭 public void close(){ try { resultSet.close(); con.close(); preparedStatement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
JDBC操作事务
注意! 增删改操作都需要提交事务
常用方法
connection.setAutoCommit(boolean flag); //设置事务是否自动提交,默认是提交的 connection.commit(); //提交事务 connection.rollback(); //回滚事务,一般不用设置,事务一般发送错误会自动回滚
下面代码是模拟一笔转账操作,A账户减少100元,B账户增加100元,两个sql操作为一个事务,同时执行成功或者失败(失败事务发生回滚)
JdbcUtility jdbc = new JdbcUtility(); try { //关闭自动提交事务 jdbc.con.setAutoCommit(false); //进行一笔转账操作,其中update()方法,参数1代表付款或者收款人,参数2代表是否收款 jdbc.update("A",true); jdbc.update("B",false); //提交一笔转账事务 jdbc.con.commit(); } catch (SQLException throwables) { try { //实际上事务会自动回滚当出现错误时 jdbc.con.rollback(); } catch (SQLException e) { e.printStackTrace(); } throwables.printStackTrace(); }