数据库连接、JDBC封装、Sql注入
数据库连接、JDBC封装、Sql注入)
1:jdbc的概念
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。
2:数据库驱动
对应的数据库驱动 。 如果我们连接mysql数据库 ,那么我们需要同一个mysql的数据库驱动
如果我们连接的是oralce数据库,那么我们需要一个oralce的数据库驱动
如果我们连接的是sqlserver,那么我们需要一个sqlserver的数据库驱动
应用程序 -->djbc --> mysql驱动 或者oracle驱动 ->数据库
3:使用jdbc连接数据库
3.1 获取驱动程序
从https://mvnrepository.com/ 仓库中获取 mysql的驱动依赖
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
3.2使用JDBC的步骤
1加载(注册)数据库
2 建立链接
3 执行SQL语句
4 处理结果集
5 关闭数据库
3.2.1注册驱动
// 注册驱动 : 只执行一次
//参数为驱动程序的全类名
Class.forName("com.mysql.jdbc.Driver");
3.2.2创建连接
//第二步 创建连接 有三个参数 第一个url 第二个 user 第三个 password
// url : 数据的地址 协议:什么样的数据库:数据库服务器的地址:端口号/数据库名称
// user : 数据库的用户名
//password : 数据库的密码
//地址还可以添加参数 &useUnicode=true&characterEncoding=utf-8 为设置字符集为utf-8 专门针对乱码
//useSSL=false 是否选择加密连接
String url="jdbc:mysql://192.168.92.182:3306/java_test? useSSL=false&useUnicode=true&characterEncoding=utf-8";
String name="root";
String pwd="123456";
Connection connection = DriverManager.getConnection(url, name, pwd);
3.2.3执行sql语句
//第三步 执行sql语句 , 获取一个执行sql语句的对象
//通过链接对象,创建一个执行sql语句对象
Statement stmt=connection.createStatement();
// sql 语句中 ,增删改 ,查
// 增删改 都是对数据进行更新的操作( 数据库中的数据发生了变化) executeUpdate---包含了(insert update delete)
//查询没有对数据进行更新操作 (数据库中的数据没有发生变化) executeQuery (select)
//定义一个sql语句
String sql="insert into user (username,userpassword,age) values ('admin','8888',10)";
//执行sql语句
int result= stmt.executeUpdate(sql);
3.2.4 处理结果
//第四步 处理结果 result 执行后的结果 处理一下结果 result 执行完毕后 ,数据库中有多少条记录受到了影响
System.out.println("语句执行完毕后的结果为:"+result);
if(result>0){
ColorPrint.greenPrintln("执行操作sql数据库成功");
}else{
ColorPrint.redPrintln("执行操作sql数据库失败");
}
3.2.5释放资源 ,关闭资源
// 第五步 ,释放资源
//关闭结果 (查询出来的结果集 ,增删改的结果不需要处理)
// 关闭执行sql语句的对象
stmt.close();
//关闭连接
connection.close();
3.3JDBC封装前的删改查操作
3.3.1更新的操作
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://192.168.92.182:3306/java_test?useSSL=false&useUnicode=true&characterEncoding=utf-8";
String name="root";
String pwd="123456";
Connection connection= DriverManager.getConnection(url,name,pwd);
Statement stmt= connection.createStatement();
String sql="update user set username='hahaha' where id =12";
int result=stmt.executeUpdate(sql);
if(result>0){
System.out.println("操作成功");
}else{
System.err.println("操作失败");
}
stmt.close();
connection.close();
3.3.2删除的操作
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://192.168.92.182:3306/java_test?useSSL=false&useUnicode=true&characterEncoding=utf-8";
String name="root";
String pwd="123456";
Connection connection= DriverManager.getConnection(url,name,pwd);
Statement stmt=connection.createStatement();
String sql="delete from user where id=4";
int result=stmt.executeUpdate(sql);
if(result>0){
System.out.println("操作成功");
}else{
System.err.println("操作失败");
}
stmt.close();
connection.close();
3.3.2查询的操作
/**
* 数据库中的查询操作
*/
Connection connection=DBUtil.getConnection();
Statement stmt=connection.createStatement();
//select * from user; --->开发的时候不能写 *
String sql="select id,username,userpassword,age from user";
ResultSet result= stmt.executeQuery(sql);
//我们从数据库中查询到了所有记录都被保存到 ResultSet 结果集对象中了
//ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前-- 所以我们要读取数据的时候,需要将光标移动到第一行
//next 方法将光标移动到下一行
// boolean b=result.next(); //第一行
//System.out.println("当前行是否有值" + b);
while(result.next()) {
// 当前行中第一列的内容
//int id = result.getInt(1);
int id=result.getInt("id");
// 当前行中第二列的内容
//String name = result.getString(2);
String name=result.getString("username");
// 当前行中第三列的内容
// String password = result.getString(3);
String password=result.getString("userpassword");
// 当前行中第三列的内容
//int age = result.getInt(4);
int age=result.getInt("age");
System.out.println(id + "," + name + "," + password + "," + age);
}
// 关闭资源---还需要关闭结果集
DBUtil.closeAll(result,stmt,connection);
4JDBC的封装
4.1 JDBC工具(util)类
package com.newcapec;
import java.sql.*;
/**
* 自定义一个工具类 ,用来保存驱动 ,创建连接 ,关闭资源
*/
public class DBUtil {
private final static String URL="jdbc:mysql://192.168.92.182:3306/java_test?useSSL=false&useUnicode=true&characterEncoding=utf-8";
private final static String NAME="root";
private final static String PWD="123456";
/*
* 加载驱动 只执行一次 ,如何保证该代码只执行一次
* 静态代码块
*/
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
*/
public static Connection getConnection(){
try {
return DriverManager.getConnection(URL,NAME,PWD);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 关闭资源
*/
public static void closeAll(ResultSet rs,Statement stmt, Connection conn){
try {
if(rs!=null) {
rs.close(); //如果要避免空指针,那么需要进行对象为空的判定
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null) {
conn.close(); //如果要避免空指针,那么需要进行对象为空的判定
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stmt!=null) {
stmt.close(); //如果要避免空指针,那么需要进行对象为空的判定
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.2和数据库对应的实体(entity)类
/**
* 和数据库中表有对应关系的类 ,我们简称实体类
*/
public class User {
//该类的属性和表中的列要一一对应
private Integer id;
private String username;
private String userpassword;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpassword() {
return userpassword;
}
public void setUserpassword(String userpassword) {
this.userpassword = userpassword;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", userpassword='" + userpassword + '\'' +
", age=" + age +
'}';
}
}
4.3MVC模式中的 M层 -模型层 ,业务逻辑操作数据库,在这里我们使用dao层 -
4.3.1dao层的接口
/**
* 操作数据库中User表的规范
*/
public interface UserDao
{
/**
* 增加用户信息的方法
* @return
*/
boolean addUser(User user);
/**
* 删除用户信息的方法
* @return
*/
boolean delUser(int id);
/**
* 更新用户信息的方法
* @return
*/
boolean updateUser(User user);
/**
* 查询用户信息的方法
*/
List<User> queryUsers();
/**
* 用户登录的方法 ,传入用户名和密码 ,
* @param user
* @return 返回值为boolean 表示是否可以正常登录
*/
boolean login(User user);
}
4.3.2 dao层的实现类
public class UserDaoImpl implements UserDao {
@Override
//参数的长度一般不要超过四个 我们可以使用一个参数来解决所有列的问题
public boolean addUser(User user) {
Connection connection= DBUtil.getConnection();
Statement stmt=null;
try {
stmt= connection.createStatement();
String sql = "insert into user (username,userpassword,age) values('"+user.getUsername()+"','"+user.getUserpassword()+"',"+user.getAge()+")";
int r= stmt.executeUpdate(sql);
if (r>0){
return true;
}
}catch (Exception e){
}finally {
DBUtil.closeAll(null,stmt,connection);
}
return false;
}
@Override
public boolean delUser(int id) {
return false;
}
@Override
public boolean updateUser(User user) {
return false;
}
@Override
public List<User> queryUsers() {
Connection connection=DBUtil.getConnection();
Statement stmt= null;
ResultSet result=null;
List<User> list=new ArrayList<>();
try {
stmt = connection.createStatement();
String sql="select id,username,userpassword,age from user";
result= stmt.executeQuery(sql);
while(result.next()){
User user=new User();
user.setId(result.getInt("id"));
user.setUsername(result.getString("username"));
user.setUserpassword(result.getString("userpassword"));
user.setAge(result.getInt("age"));
list.add(user);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 关闭资源---还需要关闭结果集
DBUtil.closeAll(result,stmt,connection);
}
return list;
}
@Override
public boolean login(User user) {
Connection connection=DBUtil.getConnection();
String sql="select id,username,userpassword,age from user where username='"+user.getUsername()+"' and userpassword='"+user.getUserpassword()+"'";// 登录的sql语句需要怎么写
Statement stmt=null;
ResultSet rs=null;
try {
stmt=connection.createStatement();
rs=stmt.executeQuery(sql);
if(rs.next()) { //如果结果集中 有内容,说明查询到了用户信息,则认为登录成功
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.closeAll(rs,stmt,connection);
}
return false;
}
}
5 Sql注入问题的解决方案
5.1 sql注入说明
所谓的sql注入 ,就是通过把SQL命令加入到请求的字符串中,最终达到七篇服务器执行恶意SQL命令。
select id,username,userpassword,age from user where username='zzz' and userpassword='123' or 'a'='a'
5.2开发中需要注意的事项
1: 永远不要信任用户的输入 。
2: 不要使用动态拼装的sql语句 ---如何在jdbc避免出现拼装的sql语句
在jdbc中如果要解决sql注入漏洞 ,我们使用PreparedStatement 来处理这问题
5.3解决办法
//修改之后的代码
@Override
public boolean login(User user) {
Connection connection=DBUtil.getConnection();
String sql="select id,username,userpassword,age from user where username= ? and userpassword= ?";// 登录的sql语句需要怎么写
//执行sql语句对象的时候 ,不要使用Statement 建议使用 PreparedStatement 对象
PreparedStatement stmt=null;
ResultSet rs=null;
try {
//PreparedStatement 在创建的时候就需要将sql语句写入到参数 ,并且sql语句中 需要插入变量的位置,我们使用占位符
stmt=connection.prepareStatement(sql);
// 对象创建之后 ,方法执行之前 ,我们需要给占位符 ? 赋值
//sql语句中有几个问号,我们就赋值 几个
//该方法有两个参数 ,第一个参数表示 你要设置?的位置 ,是第几个 ,第二个参数表示你要设置值的内容
stmt.setString(1,user.getUsername());
stmt.setString(2,user.getUserpassword());
//执行的时候不需要sql语句作为参数了
rs=stmt.executeQuery();
if(rs.next()) { //如果结果集中 有内容,说明查询到了用户信息,则认为登录成功
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.closeAll(rs,stmt,connection);
}
return false;
}