JDBC:
Java提供的一套操作数据库数据的应用编程接口,作用在于通过Java代码操作数据库;dk所提供的相应的编程接口;
JDBC组件:
- DriverManager:一系列的数据驱动程序,匹配连接使用通信协议从Java应用程序中获取合适的数据库驱动;
- Connection:所有和数据库相关的上下文操作通过该接口提供,提供数据库的事务操作,Statment对象等接口方法;
- Statment:使用创建该接口的对象来进行SQL语句的提交到数据库;
- ResultSet:存放使用SQL查询数据库返回的结果,本身是一个Set集合,多条数据是需要遍历才能拿到对应结果的;
- SQLException:所有JDBC操作异常的同意处理类;
JDBC编程步骤:
数据库连接的4个核心配置:
- 提供JDBC连接MySQL数据库,需要MySQL的驱动包;
- 请求数据库的URL;
- 数据库账号;
- 数据库密码;
数据库编程:
- 加载数据库驱动;
- 获取数据库的连接;
- 创建Statement对象;
- 执行SQL语句;
- 处理结果集 ;
代码:
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test4", "root", "123456");
Statement statement = connection.createStatement();
String sql = "select * from student";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int sid = resultSet.getInt("sid");
String sname = resultSet.getString("sname");
int sage = resultSet.getInt("sage");
String ssex = resultSet.getString("ssex");
System.out.println(sid+"\t"+sname+"\t"+sage+"\t"+ssex);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
运行结果:
1 赵雷 20 男
2 前殿 20 男
3 孙风 21 男
4 吴兰 18 女
5 孙兰 17 女
注意:
getString()、getInt()等这些方法会将数据一次性装入内存,所以数据量过大的时候,内存会装不下就会抛出异常,而getObject()方法是每次调用就去数据库获取数据,不会将数据一次性全部装入内存;
SQL注入问题
SQL注入问题::
由于dao层中执行的SQL语句是拼接出来的,其中一部分内容是用户从客户端输入的,当传入的数据中包含SQL关键字,就有可能通过这些关键字来改变SQL语句,从而执行一些特殊的操作,这种就称为SQL注入问题;
比如,有如下这样一张user表:
public class TestDemo4 {
public static void main(String[] args) {
//前端输入 用户名和秘密
String name = "zhangsan";
String passwd = "1=1 or 2345";
boolean login = login(name, passwd);
if (login) System.out.println("登陆成功");
else System.out.println("登陆失败");
}
/**
* 模拟前后台交互接口
*
* @param userName:用户名
* @param passwd:秘密
* @return true:登陆成功 false:登陆失败
*/
public static boolean login(String userName, String passwd) {
boolean result = false;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取Connection连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test5", "root", "123456");
//获取Statement对象
Statement statement = connection.createStatement();
String sql = " select * from user where name='"+userName+"' and passwd="+passwd+"";
boolean b = statement.execute(sql);
if(b) {
result = true;
}
/*
String sql = "select * from user where name = ? and passwd=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, userName);
statement.setString(2, passwd);
//执行SQL
ResultSet resultSet = statement.executeQuery();
//结果处理
if (resultSet.next()) {
result = true;
}*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
}
运行结果:
密码明明是错的,但是因为SQL语句的改变1=1是成立的,所以它也能登陆成功,这就是SQL的注入问题,解决办法就是用PreparedStatement(屏蔽的那部分代码);
如何解决SQL注入问题:
- 采用预编译的Statement对象;PreparedStatement采用预编译机制将SQL语句的主干和参数分别传输给数据库,数据库是可以分辨SQL语句中的主干和参数,这样即使SQL中带有关键字,数据库也仅仅是将其当作参数使用,关键字就不起作用;
与Statement语句一样,PreparedStatement语句同样可以完成向数据库发送SQL语句,获取数据库操作结果的功能。PreparedStatement语句习惯地称为预处理语句。
Statement对象在每次执行SQL语句时都将该语句传送给数据库,然后数据库解释器负责将SQL语句转换成内部命令,并执行该命令,完成相应的数据库操作,这种机制,每次向数据库发送一条SQL语句时,都要先转化成内部命令,如果不断的执行程序,就会加重解释器的负担,影响执行的速度。
而PreparedStatement对象,将SQL语句传送给数据库进行预编译,以后需要执行同一条语句时就不再需要重新编译,直接执行就可以了,这样就大大提高了数据库的执行速度。
尽量使用预编译的PreparedStatement,PreparedStatement的主要优势如下:
- 防止SQL注入问题;
- 使用预编译机制可以提高执行效率(执行前已经完成解析,到时候直接运行即可);
- SQL语句中的参数值是通过?的形式来代替参数,再使用PreparedStatement方法的set方法来设置参数值,相对于SQL直接拼接更加优雅;
PreparedStatement和Statement的区别:
- 语法不同:PreparedStatement使用预编译的SQL,Statement使用静态的SQL;
- 效率不同:PreparedStatement执行效率较高;
- 安全性不同:PreparedStatement可以防止SQL注入;
JDBC提供的事务相关的操作:
通过Connection接口下的方法提供的,比如设置手动、自动提交、事务的提交、回滚等等;