JDBC由来
我们的程序要去操作数据库时,都需要通过驱动进行操作。不同的数据库对应不同的数据库驱动,比如MySQL和Oracle会有不同的数据库驱动,这些驱动都是由各自的数据库公司开发。
SUN公司为了简化操作人员的操作,提供了一个JAVA操作数据库的规范,称为JDBC。它是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。数据库厂商也都会遵守这个规范,因此开发人员只需要管如何使用JDBC
要学习的是java自带的java.sql和javax.sql,除此之外还要导入一个数据库驱动包 mysql-connector-java-5.1.42.jar。包的版本根据数据库版本来
第一个JDBC程序
这个程序要去获取已经创建好的school
数据库中的account
表的信息
1、用SQLyog创建一个数据库和表,库名为school
,表名为account
2、导入mysql-connector-java-5.1.42.jar包
可以在项目目录下新建lib文件夹(与src同级),将jar包放入,之后右键lib文件夹,选择ADD AS Library
,这样就将jar包导入了
3、编写JAVA代码,读取数据并显示
import com.mysql.jdbc.Driver;
import java.sql.*;
//我的第一个JDBC程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1、加载驱动
// 也可以DriverManager.registerDriver(new com.mysql.jdbc.Driver()); ,但是会加载两次注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、登录信息和URL
String url = "jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true";
String user = "root";
String password = "123456";
// 3、建立连接 获得的是数据库对象
Connection connection = DriverManager.getConnection(url, user, password);
// 4、获取执行sql的对象
Statement statement = connection.createStatement();
// 5、执行sql,可能存在结果,查看结果
String sql = "select * from account";
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println("id:"+resultSet.getObject("id"));
System.out.println("id:"+resultSet.getObject("name"));
System.out.println("id:"+resultSet.getObject("money"));
System.out.println("===========================");
}
// 6、断开连接
resultSet.close();
statement.close();
connection.close();
}
}
第一步:加载驱动
com.mysql.jdbc.Driver
类就是一个空的构造函数和一个静态代码块,静态代码块中进行DriverManager.registerDriver(new Driver())
,所以归根到底我们直接加载这个类就可以了,让它执行静态代码块,因此推荐用上面代码中的方法Class.forName("com.mysql.jdbc.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!");
}
}
}
第二步:定义URL、用户名、密码变量
URL是固定格式jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true
3306一般是MySQL默认端口;school是你的数据库名,锁定数据库;后面是一些设置,开启Unicode,用utf8编码,进行安全认证
第三步:建立连接 获得数据库对象
Connection connection = DriverManager.getConnection(url, user, password);
利用URL、用户名和密码,我们可以连接上数据库,获得Connection对象
第四步:获取可以执行sql语句的对象
利用Connection对象可以创建能执行SQL语句的Statement对象
第五步:执行sql语句
executeQuery
可以执行查询语句,executeUpdate
可以执行其他增删改语句,execute
可以执行所有操作语句,但是需要判断SQL语句的类型。
其中查询语句获得ResultSet对象,可以用执行next方法获得下一行数据,getObject方法可以获得具体字段的值。如果知道字段类型的话,可以用更具体的数据类型,比如getString()。
其他比如插入、删除语句会返回整数,代表被修改的行数。
第六步:断开连接
查询结果对象、Statement对象、Connection对象
程序改进
改进一:新建一个properties文件,里面存放URL、用户名和密码,将这些信息单独放在一起,方便修改调用,也简化代码。
改进二:新建一个工具类,第一是通过一个静态代码块来获取properties文件中的信息,第二是定义连接和释放连接的方法,方便调用。
db.properties
src目录下
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=false
user=root
password=123456
JdbcUtils.class
工具类:1、获取配置文件数据 2、加载驱动 3、连接方法 4、释放连接方法
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
public static String driver = null;
public static String url = null;
public static String user = null;
public static String password = null;
//提取配置文件内的信息
static{
try{
//通过反射获取配置文件,并转为流的形式
InputStream stream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
//新建配置对象,并加载数据
Properties properties = new Properties();
properties.load(stream);
//获取数据
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//加载驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//连接方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//释放连接方法,如果没有结果就输入null即可
public static void release(ResultSet resultSet, Statement statement, Connection connection) throws SQLException {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if(connection!=null){
connection.close();
}
}
}
JdbcUtilsInsert
测试插入操作
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtilsInsert {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//连接
connection = JdbcUtils.getConnection();
//执行
statement = connection.createStatement();
String sql = "insert into `account`(id, name, money) values (10,'yqb',100)";
int i = statement.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(resultSet, statement, connection);
}
}
}
SQL注入问题
在java中,我们的SQL语句就是一个字符串!我们通过将这个字符串传入Statement的execute方法中来进行执行。因为字符串是可以拼接的,因此会出现SQL注入的问题
举例:我们要根据id
和name
字段去app_user表中去查询数据。我们的id和name都设置成了变量,我们准备通过字符串拼接的方法得到我们的SQL字符串,然后再执行这个SQL字符串
String id = "0 or 1=1 ";
String name = "yqb' or '1";
String sql = "select * from app_user where id = "+ id + " and name = '"+ name +"'";
拼接后,对应的SQL语句其实是:
SELECT * FROM app_user WHERE id = 0 OR 1=1 AND NAME = 'yqb' OR '1'
这样,这个Where永远成立,起不到查询的效果,而且这样也可以得到所有用户的数据,很不安全,这就是SQL注入问题
解决注入问题
利用PreparedStatement类替换Statement类可以解决SQL注入问题!这两个类的用法相似,但也有不同的地方
步骤:1、在定义sql字符串语句中,用?
占位符为变量进行占位 2、获得PreparedStatement对象的同时,对sql语句进行预编译 3、执行
举例(片段,其他地方与上面代码类似):
//定义sql字符串,?进行占位
String sql = "select * from account where id = ? and name = ?";
//对sql预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//赋值,第一个参数代表是第几个问号,第二个参数代表要赋的值
preparedStatement.setInt(1,1);
preparedStatement.setString(2,"A");
//执行,由于之前预编译,因此不再需要sql语句了
ResultSet resultSet = preparedStatement.executeQuery();
PreparedStatement防止SQL注入的本质在于:把传递进来的参数当作一个字符看待,即在整体外面加上引号。而内部本身的引号会被转义掉
JDBC操作事务
1、连接 2、关闭提交,开启事务 3、操作 4、提交 5、发生异常就会滚 6、释放
下面测试代码,需要前面的JdbcUtils.class和db.properties代码。在try中测试事务并提交,在catch中回滚,最终都要释放。
import Jdbc.lesson2.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
try {
//获得连接
connection = JdbcUtils.getConnection();
//关闭自动提交,同时自动开启事务
connection.setAutoCommit(false);
//第一个事
String sql1 = "update account set money = money - 500 where name = 'A'";
statement = connection.prepareStatement(sql1);
statement.executeUpdate();
//第二个事
String sql2 = "update account set money = money + 500 where name = 'B'";
statement = connection.prepareStatement(sql2);
statement.executeUpdate();
//提交
connection.commit();
} catch (Exception throwables) {
connection.rollback();
} finally {
JdbcUtils.release(null,statement,connection);
}
}
}