JDBC
JDBC
前言
了解JDBC之前,我们想想为什么需要有JDBC这个接口。JDBC是java提供给我们去跟数据库做连接的一个接口。有些人会有疑惑了。我们直接在类里就可以导入数据库驱动,添加连接,然后对数据库进行增删改查也可以呀,所有为什么要有JDBC呢。
直接注册驱动
DriverManager.registerDriver(new Driver());
获取连接
Connection conn = DriverManager
.getConnection("jdbc:mysql
://localhost:3306/day20?
characterEncoding=UTF8", "root", "root");
如果有这样一个场景,公司开发一个项目,开发到一半发现数据库不好用要换掉,可是我们的数据库的注册 创建 实现功能的程序都是直接绑定在一起的,如果修改数据库所有的程序都要进行修改,耦合性太高,牵一发而动全身。
解决方法
这时候JDBC就派上用场了,java写程序都是尽量去依赖于抽象,降低耦合性。我们java代码调用JDBC,让JDBC去跟数据库建立起连接,这样的话底层数据库不管如何变跟我们写的程序没有任何关系,这样就起到一个解耦的作用。
注释得比较清楚
@Test
public void testDeleteById() throws Exception {
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获得连接对象
Connection conn = DriverManager
.getConnection("jdbc:mysql://localhost:3306/day20?characterEncoding=UTF8", "root", "123");
//创建statement对象(这个对象就是执行SQL语句的对象)
// 创建Statement对象:
//这个对象可以将要执行的SQL语句发送给数据库服务器
//进行执行,并且拿到执行结果
Statement stm = conn.createStatement();
//编写SQL语句并执行
String sql = "delete from user where id=4";
stm.executeUpdate(sql);
//5. 关闭资源
stm.close();
conn.close();
**现在还有两个问题,第一我们数据库的注册创建还有销毁都是重复性代码,第二我们如果需要要修改驱动或是修改连接对象时需要去底层源码修改,这不符合我们的开闭原则,属于硬编码,要尽量避免。
**
配置文件来进行定义参数
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/db1
jdbc.username = root
jdbc.password = root
定义工具类解决代码复用性的问题(注释很详细)
public class JDBCUtil {
private static String username;
private static String password;
private static String url;
private static String driverName;
static {
InputStream is = null;
try {
//读取配置文件的代码只需要执行一次
//创建Properties对象,
// 用于加载properties文件
Properties properties = new Properties();
//将要加载的配置文件转成InputStream
ClassLoader classLoader =
JDBCUtil.class.getClassLoader();
is = classLoader
.getResourceAsStream("jdbc.properties");
//properties对象加载流
properties.load(is);
//从properties对象中,根据name获取value
driverName
= properties.getProperty("jdbc.driver");
username
= properties.getProperty("jdbc.username");
password
= properties.getProperty("jdbc.password");
url = properties.getProperty("jdbc.url");
//注册驱动:这句代码只需要执行一次即可
Class.forName(driverName);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Connection getConnection()
throws Exception {
//获得连接对象
Connection conn = DriverManager
.getConnection(url, username,
password);
return conn;
}
// 关闭资源
public static void close(Statement stm,
Connection conn) throws SQLException {
close(null,stm,conn);
}
public static void close(ResultSet rst,
Statement stm,Connection conn) throws SQLException {
if (rst != null){
rst.close();
}
if(stm != null){
stm.close();
}
if (conn != null) {
conn.close();
}
}
SQL注入问题
Statement编译sql语句时是把参数进行拼接,如果有人在参数尾部加上 ’ or ‘’ = ’ 时,你的sql语句就会变成
SELECT * FROM user WHERE username ='zs'
AND password = '' or '' = ''
这样,那你的sql语句就会有SQL注入问题。
preparedStatement 预编译SQL语句对象, 是Statement对象的子接口。
特点:
- 性能要比Statement高
- 会把sql语句先编译,格式固定好,用户无法通过SQL注入改变SQL语句的格式
- sql语句中的参数会发生变化,过滤掉用户输入的关键字(eg: or)
@Test
public void testAdd() throws Exception {
//目标: 使用preparedStatement对象,
//进行预编译执行SQL语句
String username = "jay";
String password = "123456789";
String nickname = "周杰棍";
//获得连接
Connection conn = JDBCUtil.getConnection();
//编写参数化的SQL语句: 需要传入数据的地方
//使用"?"占位符代替,并且进行预编译
String sql = "insert into user
(username,password,nickname) values (?,?,?)";
//预编译: 固定SQL语句的格式
PreparedStatement pstm =
conn.prepareStatement(sql);
//设置占位符位置的参数
pstm.setString(1,username);
pstm.setString(2,password);
pstm.setString(3,nickname);
//执行SQL语句
pstm.executeUpdate();
//关闭资源
JDBCUtil.close(pstm,conn);
}
使用preparedStatement就完美避免了SQL注入问题。
写的有些粗糙,希望对大家有帮助。