1.JDBC介绍
jdbc(java database connectivity)为java开发者使用数据库提供了统一的编程接口,它由一组java类和接口组成。
JDBC需要用到的类和接口有:
DriverManager、Connection、Statement、ResultSet
2. mysql-connector-java下载
本机的mysql版本是5.7.26 win32的,所以本章访问mysql都以该版本为例:
然后进入https://dev.mysql.com/downloads/connector/j/下载mysql-connector-java.jar包,用于连接mysql
如下图所示,只有8.0.19版本,那我们下载它就好了,反正不管64位还是32位都能访问:
下载解压后,就有个mysql-connector-java-8.0.19.jar:
接下来就来测试,能不能访问
3.JDBC使用过程
3.1 通过DriverManager. registerDriver(Driver driver)来注册驱动程序
需要注意,new Driver的时候,需要选择com.mysql.cj.jdbc.Driver:
因为com.mysql.jdbc.Driver已经被弃用了.
PS:也可以直接将DriverManager. registerDriver(Driver driver)改为:
Class.forName("com.mysql.cj.jdbc.Driver"); //加载一下这个类就可以注册驱动,因为mysql Driver类的静态代码块中已经调用了registerDriver()来注册驱动程序.
3.2 然后通过 Connection DriverManager.getConnection(String url, String user, String password)来连接数据库,并获取Connection对象
url: 填入“jdbc:子协议://ip地址:端口号/数据库名” ,如果是mysql则填入“jdbc:mysql://localhost:3306/数据库名”
针对mysql-connector-java-8.0以上的版本,则还要追加"?characterEcoding=utf-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"
username:mysql用户名
password:mysql密码
3.3 通过Connection对象获取statement对象
Statement statement = connection.createStatement();
3.4 通过statement对象的executeQuery(String)来执行查询sql语句,并返回ResultSet数据库结果集
比如:
ResultSet resultSet = statement. executeQuery("select * from student"); //获取student表里的数据
除此之外还有int executeUpdate(String sql)方法.用来实现INSERT、UPDATE 或 DELETE 语句,返回值表示执行sql语句之后影响到的数据行数 (后面示例有讲)
3.5 然后通过ResultSet来读出query内容
ResultSet常用方法如下:
boolean first(); //移到内容第一行数据处 boolean last(); //移到内容最后一行数据处 int getRow() ; //获取当前光标处于的行号 boolean isLast() //获取光标是否位于此 ResultSet 对象的最后一行。 boolean next(); //移到下一行数据处,然后就可以通过getXXX()获取完当前一行数据后,则通过next()来移动到下行继续getXXX(),直到next()返回为false为止 boolean previous(); //移到上一行数据处 String getString(String columnLabel); //获取当前一行的columnLabel列名的内容 String getString(int columnIndex); //获取当前一行的第columnIndex列的内容,第一列是从1开始的. String getInt (String columnLabel); //获取当前一行的columnLabel列名的内容 String getInt(int columnIndex); //获取当前一行的第columnIndex列的内容,第一列是从1开始的. //...除此之外,还有getFloat(),getLong(),getShort(),getURL(),getBoolean(),getRowId()
PS:获取到ResultSet后,必须先next()一次才能getXXX(),来获取内容
3.6 访问结束后,释放Mysql资源(毕竟mysql连入个数是有限的)
try { if(resultSet!=null){ resultSet.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(statement!=null){ statement.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(connection!=null){ connection.close(); } } catch (SQLException e) { e.printStackTrace(); }
4.本章要访问的数据库以students为例:
5.首先来写JdbcUtils工具类
JdbcUtils工具类里主要写getConnection(),releaseResc()这两个类,这样避免后续的重复代码产生.
JdbcUtils.java代码如下所示:
public class JdbcUtils { private static String driver; private static String url; private static String user; private static String pwd; static{ driver = "com.mysql.cj.jdbc.Driver"; url = "jdbc:mysql://localhost:3306/students?characterEcoding=utf-8&" + "useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"; user = "root"; pwd = "sql"; } //获取一个链接mysql的Connection对象 static public Connection getConnection(){ try { Class.forName(driver); Connection connection = DriverManager.getConnection(url,user,pwd); return connection; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 释放Mysql资源(毕竟mysql连入个数是有限的) * @param resultSet 结果集 * @param statement * @param connection 链接 */ public static void releaseResc(ResultSet resultSet, Statement statement, Connection connection) { try { if(resultSet!=null){ resultSet.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(statement!=null){ statement.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if(connection!=null){ connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
6.数据库查询示例
查询所有学生的信息:
@Test public void jdbcQuery(){ ResultSet resultSet = null; Statement statement = null; Connection connection = null; try { connection = JdbcUtils.getConnection(); //通过JdbcUtils获取connection statement = connection.createStatement(); String sql = "select * from student"; resultSet = statement.executeQuery(sql); while(resultSet.next()){ String name = resultSet.getString("name"); String score = resultSet.getString("score"); String classs = resultSet.getString("class"); System.out.println("姓名:"+name+" 成绩:"+score+" 班级:"+classs); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { JdbcUtils.releaseResc(resultSet, statement, connection); //释放资源 } }
打印如下所示:
7.数据库插入示例
@Test public void jdbcInser(){ ResultSet resultSet = null; Statement statement = null; Connection connection = null; try { connection = JdbcUtils.getConnection(); statement = connection.createStatement(); String name = "小f"; int score = 99; String classs = "初2-4班"; String sql = "INSERT INTO student(name,score,class) " +" values('"+name+"','"+String.valueOf(score)+"','"+classs+"')"; int result = statement.executeUpdate(sql); //executeUpdate:用来实现INSERT、UPDATE 或 DELETE 语句,返回值表示执行sql语句之后影响到的数据行数 System.out.println("插入了"+result+"条数据"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { JdbcUtils.releaseResc(resultSet, statement, connection); //释放资源 } }
运行打印:
查看数据库:
8.数据库更新示例
将所有低于60分的同学的成绩改为0:
@Test public void jdbcUpdate(){ ResultSet resultSet = null; Statement statement = null; Connection connection = null; try { connection = JdbcUtils.getConnection(); statement = connection.createStatement(); String sql = "update student SET score='0' WHERE score<60"; int result = statement.executeUpdate(sql); //executeUpdate:用来实现INSERT、UPDATE 或 DELETE 语句,返回值表示执行sql语句之后影响到的数据行数 System.out.println("更新了"+result+"条数据"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { JdbcUtils.releaseResc(resultSet, statement, connection); //释放资源 } }
查看数据库:
9.SQL 注入攻击
Statement采取直接编译 SQL 语句的方式,扔给数据库去执行,所以很容易进行被SQL注入攻击.
比如:
我们登陆执行时需要执行:
statement.executeQuery("select id from users where name ='"+username+"' and password = '"+password+"'");
而黑客则将字符串直接改为:
statement.executeQuery("select id from users where name ='"+username+"' or '1==1' and password = '"+password+"'");
就可以直接乱输入密码也能实现登录了,所以java中提供了另一个类PreparedStatement, 采用"?"占位符预编译,再填充参数,用来避免SQL注入攻击.
PreparedStatement类介绍
采用"?"占位符预编译,再填充参数,然后通过setXXX()来填充参数.比如setString():
setString(int parameterIndex, String x); //向第parameterIndex个占位符填入x内容 // parameterIndex:第一个?占位符是1,第二个是2.... //...除了该方法之外,还有setFloat(),setLong(),setBoolean()....等等
修改登录界面之PreparedStatement使用如下所示:
public static boolean login(String username,String password){ Connection connection = JdbcUtils.getConnection(); //获取 try { String sql = "select id from users where username =? and password = ?"; //要运行的sql语句,通过?来替换登录账号和密码 PreparedStatement preparedStatement = connection.prepareStatement(sql); //第一个? 用username字符串去替换 preparedStatement.setString(1, username); //第二个? 用password字符串去替换 preparedStatement.setString(2, password); ResultSet resultSet = preparedStatement.executeQuery(); return resultSet.next(); //有值则返回true,否则返回false; } catch (SQLException e) { e.printStackTrace(); return false; } }