JDBC学习笔记!
作者:互联网
JDBC:Java DataBase Connectivity
JDBC是sun公司制定的一套接口,目的是为了进行面向接口编程。因为每个数据库底层实现原理不一样,这就需要制定这样一套接口来连接各大数据库。
为什么面向接口编程:解耦合。降低程序的耦合度,提高程序的扩展力。
-
JDBC编程六步:
-
第一步:注册驱动(告诉java程序,即将要连接哪个品牌的数据库)
DriverManager.registerDriver(Driver driver);
- 第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开,这属于进程之间的通信,重量级,使用完之后一定要关闭)
Connection conn = DriverManager.getConnection(String url,String user,String password);
url是网络资源定位符,由协议,ip地址,端口号,虚拟目录,文件名组成。
- 第三步:获取数据库操作对象(用来专门执行Sql语句)
Statement stem = conn.createStatment()
- 第四步:执行Sql语句(DQL,DML…)
String sql = "即将要执行的sql语句";
int count = stem.executeUpdate(String sql)//这条语句只能执行update,delete,insert语句,sql为要发送给数据库的sql语句
返回整数表示这条语句改变了数据库多少信息条数
- 第五步:处理查询结果集(只有当第四步执行的是selecet语句的时候,才有这第五步查询结果集)
- 第六步:释放资源(使用完资源之后一定要关闭资源。java和数据库属于进程之间的通信,开启之后一定要关闭)
- 最后的释放资源一定要放在finally语句中,并且要分开try catch,目的是为了保证一定能执行
怎么有效记住这六步,首先,注册驱动,如果要与数据库产生关系首先要连接起来,然后要执行Sql语句的话,要先获取数据库对象,然后才能对数据库进行操作,然后就是执Sql语句,对结果集进行处理,最后释放资源,关闭通道。
import java.sql.*;
public static void main(String[] args){
Connection conn = null;
Statement stem = null;
try{
//注册驱动
//DriverManager.registDriver(new com.mysql.jdbc.Driver());这种方法不常使用,有一种更好的方法就是使用类加载
//Class.forName(String path);
Class.forName("com.mysql.jdbc.Driver");
//使用类加载可以直接执行类中的静态代码块
//获取连接
String url = "*****";
String user = "******";
String password = "*********";
conn = DriverManager.getConnection(url,user,passwoer);
//获取数据库操作对象
stem = conn.createStatement();
//执行sql语句
String sql = "sql语句";
int count = stem.executeUpdate(sql);
System.out.println(count == 1? "数据库连接成功" : "数据库连接失败");
}catch(SQLException e){
e.printStackTrace();
}finall{
//释放资源
if(stem != null){
try(){
stem.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn != null){
try(){
conn.close();
}catch(SqlException e){
e.printStackTrace();
}
}
}
}
在实际开发中,我们将用户名及密码通常写在配置文件中,再通过资源绑定器(ResourceBundle来获取)
import java.sql.*;
import java.uti.*;
public static void main(String[] args){
//将用户名,密码,ip,协议写在属性配置文件里,然后通过ResourceBundle获取用户名,密码
Connection conn = null;
Statement stem = null;
ResultSet rs = null;//用来处理查询结果集
ResourceBundle re = ResourceBundle.getBundle("jdbc");
String user = re.getString("user");
String password = re.getString("password");
String url = re.getString("url");
String driver = re.getString("driver");
try{
Class.forName(driver);
conn = DriverManager.getConnection(url,user,passwoer);
stem = conn.createStatement();
String sql = "sql语句";
int count = stem.executeUpdate(sql);//支持增删改语句
rs = stem.executeQuery(sql);//获取指定的sql查询语句,返回单个ResultSet对象
/*
对查询结果集进行遍历
rs.next()将当前光标移至下一行,如果下一行有数据返回true,没有返回false
while(rs.next()){
//通过指定列获取查询结果集中的内容
String no = rs.getString(1);
String nnum = rs.getString(2);
String name = rs.getString(3);
//这种方法更为健壮
//get方法中的字符串是sql查询语句中的名字,
//比如select sno as no from t_student get方法里面的字符串应该是no而不是sno
String no = rs.getString("no");
String num = rs.getString("num");
String name = rs.getString("name");
//并不是只有getString()一种方法,还有getInt(" "),getDouble("")等方法
}
*/
System.out.println(count == 1? "成功" : "失败");
}catch(SQLException e){
e.printStackTrace();
}finall{
if(stem != null){
try(){
stem.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn != null){
try(){
conn.close();
}catch(SqlException e){
e.printStackTrace();
}
}
}
}
使用JDBC的好处
- 程序员如果要开发访问数据库的程序,只需要调用JDBC接口中的方法即可,不用关注类是如何实现的。
- 使用一套java代码,就可以访问多个JDBC支持的数据库
使用JDBC过程中使用的类
DriverManager(Conection conn = DriverManager.getConnection();连接数据库)
Statement(Statement stem = conn.createStatement();创建数据库操作对象)
ResultSet rs = stem.executeQuery(String sql);执行选择语句用executeQuery()
int count = stem.executeUpdate(String sql);执行增删改语句
Sql注入
-
Sql注入的根本原因:用户输入的信息中含有Sql语句中的关键字(比如密码输入fdsa’ or ‘1’ = '1 在执行select语句后形成一条新的语句 select * from t_user where loginName = ‘fdsa’ and lobinPwd = ‘fdsa’ or ‘1’ = ‘1’),并且这些关键字参与了sql语句的编译过程,导致sql语句的原意被扭曲,进而导致sql注入。
-
解决sql注入
- 只要让让用户输入的信息不参与sql语句的编译,就不会产生sql注入的问题。
- 将Statement数据库操作对象改为PreparedStatement
- PreparedStatement接口继承了java.sql.Statement,是属于预编译的数据库操作对象,PreparedStatement的原理:预先对sql语句的框架进行编译,然后再给sql语句传值。
原语句:
Statement stem = null;
stem = conn.getConnection();
String sql = "select * from t_user where loginName = '"+loginName+"'and loginPwd = '"+loginPwd+"'"
stem.executeQuery(sql);
修改后:
PreparedStatement ps = null;
//?被称作占位符
String sql = "select * from t_user where loginName = ? and loginPwd = ?";
ps = conn.prepareStatement(sql);
//给占位符赋值,赋的是什么值就用set什么,jdbc的下标是从1开始的
ps.setrString(1,loginName);
ps.setString(2,loginPwd);
ps.execureQuery();
//然后接下来的executeQuery()就不用再传递sql语句了;
Statement与PreparedStatement的区别
- Statement存在sql注入问题,PreparedStatement解决了sql注入的问题
- Statement是编译一次执行一次,PreparedStatement是编译一次执行n次,效率要比Statement执行效率高
- PreparedStatement会在编译的时候做类型的安全检查
- 综上所述,PreparedStatement用的次数比较多,在需要sql注入(sql语句拼接)的时候用到Statement
事务
- jdbc中的事务是自动提交的,即执行一句,提交一句,所以就需要使用到Connection类的setAutoCommit(boolean flag)方法,里面传一个boolean类型的值,当出现异常的时候,在catch中执行rollback()方法,当事务顺利执行完的时候执行commit()语句,表示提交事务。
JDBC工具类的封装
- 由于在使用过程中有些代码频繁的使用,需要定义一个工具类类存放这些频繁使用的语句。(DBUtils)
public class Test{
public static void main(String[] args){
Connection conn = null;
PreparedStatement ps =null;
ResultSet rs = null;
try{
//获取数据库操作对象
conn = DBUtil.getConnection();
//sql语句
String sql = "select * from t_user where name = ?";
ps = conn.prepareStatement(sql);
//模糊查询
ps.setString(1,"_A%");
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 释放资源
DBUtils.close(conn,stem,rs);
}
}
}
public class DBUtils{
private DBUTils{};
static{
//静态代码块在类加载的时候执行且执行一次
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(Execption e){
e.printStackTrace();
}
}
//由于在调用这个类的类中有try catch所以这里直接抛出Exception即可
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(url,user,password);
}
public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
if(rs != null){
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(stem != null){
try{
stem.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
行级锁(行级锁)
- 事务必须排队执行,事务锁住了,不允许并发
- 乐观锁:支持事务并发,不需要排队,只不过需要一个版本号。
标签:语句,JDBC,String,rs,笔记,stem,学习,sql,conn 来源: https://blog.csdn.net/m0_48847163/article/details/115440643