什么是JDBC?
JDBC:即为 Java DataBase Connectivity (java语言连接数据库)
JDBC的本质: 其实是SUN公司制定的一套接口(inferace),一套面向各类数据库的接口。而接口都有调用者和实现者
为什么SUN指定一套JDBC接口?
因为每一个数据库的底层实现原理都不一样。Oracle数据库,mysql数据库等数据库产品都有自己不同的实现原理。
谁是实现者?谁是调用者?
这里的实现者就是各大数据库厂商,例如Oracle、MySQL、SQL Server、PostgrcSQL、 DB2.........他们去实现这套接口,供调用者能去使用,从而能从中赚取利益(不然干这活干嘛)。
这里的调用者就是我们这些数据库的使用者(各大公司呀,大厂之类的)。实现接口的活有人干了的话,我们就能够根据他们实现接口的这一套来使用了。
面向接口调用,面向接口写实现类,这都属于面向接口编程。为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。(多态机制就是面向抽象编程)
此处主要是介绍MySQL数据库与java的连接
JDBC编程六步
第一步:注册驱动(告诉java程序,即将要连接的是那个品牌的数据库)
第二步:获取连接(表示jvm的进程与数据库进程之间的通道打开了,这是属于进程之间的通信,重量级的,使用完之后一定要关闭。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行sql语句(DQL,DML............)
第五步:处理查询结果(只有当第四步执行的select语句的时候,才有这第五步处理查询结果集)
第六步:释放资源(使用完资源后,一定要关闭资源。Java和数据库属于进程间的通信,,开启之后一定要关闭)
1.注册驱动
//1.注册驱动
//第一种方式
Driver driver=new com.mysql.cj.jdbc.Driver(); //多态,父类型引用指向子类型对象
DriverManager.registerDriver(driver);
/*第二种方式:
更常用,因为参数是一个字符串,字符串可以写到xxx.properties文件中。
且以下方式不需要接受返回值,因为我们只想用他的类加载动作,类加载后静态代码块执行,
静态代码块中完成注册驱动*/
Class.forName("com.mysql.cj.jdbc.Driver");
2.获取连接
//2.获取连接
Connection conn=null;
String url="jdbc:mysql://localhost:3306/mydb"; //指定你已创建好的数据库
String user="root"; //指定账户,此处为root账户
String password="213215"; //指定你登录MySQL所设置的密码
conn=DriverManager.getConnection(url,user,password);
//直接在参数中指定
//conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","213215");
System.out.println("数据库连接对象为"+conn);
3.获取数据库操作对象
//3.获取数据库操作对象
Statement stmt=null;
stmt=conn.createStatement(); //Statement专门执行sql语句的
4.执行SQL语句
例1:DML语句
//4.执行sql语句
String sql="insert into mytable(name,sex) values('zs','nan')";
int count=stmt.executeUpdate(sql); //返回值是“影响数据库中的记录条数”
System.out.println(count==1?"保存成功":"保存失败");
例2:DQL语句
//4.执行sql语句
ResultSet rs = null;
String sql = "selete * from mytable";
//专门执行DQL语句的方法。rs就相当于是查询结果的一张表
rs = stmt.executeQuery(sql);
5.处理查询结果集(DQL语句才有查询结果集)
//5.处理查询结果集
//上面的rs就相当于是查询结果的一张表
while (rs.next()) {
/*
以列的下标获取,jdbc中所有的下标从1开始,不是从0开始
String empno=rs.getString(1);
String ename=rs.getString(2);
String sal=rs.getString(3);
System.out.println(empno+","+ename+","+sal);
*/
//以列的名字获取
String name=rs.getString("name"); //注意:列名称不是表中的列名称,是查询结果的列名称
String sex=rs.getString("sex");
System.out.println(name+","+sex);
/*
指定特定类型取出
int empno = rs.getInt("empmo");
String ename = rs.getString("ename");
double sal = rs.getDouble("sal");
System.out.println(empno + "," + ename + "," + (sal + 100));
*/
6.释放资源(放在finally语句中,以保证一定释放资源)
//6.释放资源
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
关于SQL注入问题
//思考:输入这样的账号和密码能登录成功吗?
//账号:'zs' OR '1'='1'
//密码:'123'OR '1'='1'
SELECT * FROM Users WHERE Username='zs' OR '1'='1' AND Password='123'OR '1'='1'
结果是可以登录成功,这种现象被称为Sql注入(存在安全隐患)。
根本原因:
用户输入的信息含有SQL语句关键字,并且这些关键字进入编译过程,导致SQL语句原意被扭曲,进而产生一些危险的信息安全隐患。
解决方案 :
可以推测,解决 SQL注入关键就是,让用户提供的信息中即使含有SQL语句关键字,但这些关键字没有参与编译的话,就不会起到扭曲原意的作用。于是可以想到,那为什么不先对语句进行编译,再由用户输入进行传值呢?
如何才能做到先编译呢?(使用PerparedStatement代替Statement)
想要用户提供的信息不参与编译,则需要使用java.sql.PerparedStatement。
PerparedStatement接口继承了java.sql.Statement,属于预编译的数据库操作对象,它可以编译一次,从而执行多次。
PerparedStatement原理就是预先对sql语句的框架进行编译,然后再给SQL语句传值。
执行过程:
//Sql语句框子。其中一个?表示一个占位符,一个?接受一个“值”,注意,占位符不能用单引号括来。
//第一步:写SQL语句
String sql = "selete * from mytable where name=? and sex=? ";
//程序执行到此处,会发送sql语句框子给DBMS,然后DBMS进行sql语句的预先编译
//第二步,获取预编译对象pstmt
pstmt = conn.prepareStatement(sql);
//第三步,给占位符?传值(第一个问号下标是1,第二个问号下标是2,jDBC中,所有下标从1 开始)
pstmt.setString(1,张三);
pstmt.setString(2,男);
//第四步,执行sql
rs = pstmt.executeQuery(sql);
需要注意的是:并不是说有了预编译的使用,那么Statement是不是就可以彻底抛弃了呢?
显然这样的观点是错误的?
对于只执行一次的SQL语句(不需要考虑SQL注入时)选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的.因为相比Statement,PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行.
最后,关于以上JDBC的基本使用,还可以自己去编写一个JDBC的工具类来方便自己使用
public class DBUtil {
//工具类中的构造方法都是私有的,因为工具类中的方法都是静态的,不需要new对象,直接采用类名调用
private DBUtil() {
}
//静态代码块在类加载时执行,并且只执行一次。
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取数据库连接对象,返回值为连接对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "213215");
}
//关闭资源
public static void close(Connection coon, Statement stmt, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(coon!=null){
try {
coon.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
以上就是我本人(新手菜鸟一个)对自己学到的JDBC的简单内容的简单总结,主要是拿来利于后面的复习,也是我发的第一篇博客,如有错误,希望大家指出,定然接受并及时改正。