详解Java基础知识——JDBC
jdbc
java database connectivity,java数据库连接,为了降低操作数据的难度,java提供jdbc,按照java面向对象特点,对操作进行了很多封装。
jdbc提供了很多接口,然后不同数据库厂商去实现这个接口,到底底层如何去实现,不同的数据库不一样,不同的数据库厂商需要提供接口实现类(驱动类、驱动程序 driver、驱动)
我们连接不同的数据库,我们只需要使用不同的驱动即可。
j:java:提供访问数据库的规范(接口),
dbc:接口的实现,厂商去实现这个接口。
jdbc是一种用于执行sql语句的java api.
版本号
1.1.1 major. minor. build
major:项目由架构、大规模的变化
minor:有新功能的时候
build:编译版本
jdbc开发
java程序使用第三方提供工具框架,都需要导入jar包
可以通过以下网址搜索找到mysql的相关jar包
下载好jar包后,在于src同级的目录下,建立一个lib文件夹,添加jar包,并添加依赖
代码实现
通过一个简单的案例来实现jdbc的使用
import java.sql.*; public class demo02 { public static void main(string[] args) throws classnotfoundexception, sqlexception { //1注册驱动 class.forname("com.mysql.jdbc.driver"); //2建立连接 string url = "jdbc:mysql://localhost:3306/mydb01"; string usernname = "xxx"; //登录数据库的账号 string password = "xxxx"; //登录数据库的密码 connection conn = drivermanager.getconnection(url, usernname, password); //3获取执行sql语句的对象 statement statement = conn.createstatement(); //4获取数据库返回的结果 string sql = "delete from emp where empno = " +"7499"; string sqlupdate = "update emp set sal = "+10000+" where empno = " +"7369"; string sqlinsert = "insert into emp values(2018,\"boss\",\"king\",null,\"2018-8- 8\",15000,10000,10);"; //5处理数据集 int i = statement.executeupdate(sql); int s = statement.executeupdate(sqlupdate); int ins = statement.executeupdate(sqlinsert); system.out.println(i + "行受到影响----删除"); system.out.println(s + "行受到影响----更新"); system.out.println(ins + "行受到影响----插入"); //6关闭连接 statement.close(); conn.close(); } }
使用jdbc的顺序
- (1)注册数据库驱动
- (2)和数据库建立连接
- (3)获取执行sql语句的对象
- (4)获取数据库返回的结果
- (5)处理数据集(逻辑代码)
- (6)释放资源,关闭连接
常用类
connection
通过配置文件可以创建一个connect对象
statement
- 通过connect对象获取操作数据库的statement对象,
- 通过它来实现对数据库增删改查操作。
- executequery():查,返回数据集
- executeupdate():增删改,返回int的数据,影响的行数
resultset
数据集,可以理解就是一个集合。
取出数据:
- 通过下标:从1开始
- 通过字段名:sql语句中select后面跟的字段,有可能和数据库一样,也可能不一样
jdbc的优化
平时开发和项目上线之后使用的数据库是不一样的,不是同一个
这也就是我们说的,开发环境不一样
开发环境不一样,使用的数据库也就不一样,那么上面的数据库中配置的三要素就要进行修改
而这种修改是人工操作的,人工操作就有存在了失误,而修改之后的.java文件,也要重新编译,这也可能出现错误
假设项目上线,需要以下四个步骤:
测试环境-->修改配置 -->重新编译-->生产环境
如果想要避免上述出现的失误的情况,就要绕开中间的两个步骤
解决的方法就是,配置文件,添加配置文件,将要修改的配置信息存放到配置文件中,每次读取信息从配置文件中读取
而配置文件的位置是固定的,也不会重新编译,这样就可以降低风险
java中用io流也可以读取配置文件,通过一个专有的类properties也可以读写配置文件
io读取配置文件
import java.io.bufferedreader; import java.io.filereader; import java.io.ioexception; import java.sql.*; import java.util.properties; public class ioreadprop { public static void main(string[] args) throws classnotfoundexception, sqlexception, ioexception { //1注册驱动 class.forname("com.mysql.jdbc.driver"); string[] para = read(); //2建立连接 string url = para[0]; string usernname = para[1]; string password = para[2]; connection conn = drivermanager.getconnection(url,usernname,password); //3获取执行sql语句的对象 statement statement = conn.createstatement(); //4获取数据库返回的结果 string sql = "select * from emp"; resultset resultset = statement.executequery(sql); //5处理数据集 try { while (resultset.next()){ //.getxxx方法中的参数 1,字段名 2.字段的下标 int empno = resultset.getint("empno"); string ename = resultset.getstring("ename"); string job = resultset.getstring(3); date date = resultset.getdate(5); system.out.println("empno:"+empno+", ename:"+ename+", job:"+job+", date:"+date); } } catch (exception e){ e.printstacktrace(); } finally { //6关闭连接 resultset.close(); statement.close(); conn.close(); } } public static string [] read()throws ioexception { filereader fr = new filereader( "e:\\javalearning\\src\\jdbc\\jdbc.properties" ); //创建 写入 缓冲区 bufferedreader bufferedreader = new bufferedreader( fr ); string [] str = new string[3]; for(int i =0 ;i < 3;i++){ str[i] = bufferedreader.readline().split("=")[1].replace(";","").trim(); } bufferedreader.close(); fr.close(); return str; } }
properties读取配置文件
import java.io.*; import java.sql.*; import java.util.iterator; import java.util.properties; public class propreadprop { public static void main(string[] args) throws classnotfoundexception, sqlexception, ioexception { //1注册驱动 class.forname("com.mysql.jdbc.driver"); //用户数组存放数据库信息 string[] para = new string[3]; //读取配置文件 int i = 0; properties prop = new properties(); fileinputstream fileinputstream = new fileinputstream("e:\\javalearning\\src\\jdbc\\jdbc.properties"); inputstream in = new bufferedinputstream(fileinputstream); prop.load(in); iterator<string> it = prop.stringpropertynames().iterator(); while (it.hasnext()) { para[i] = prop.getproperty(it.next()); i++; } in.close(); //2建立连接 string url = para[0]; string usernname = para[1]; string password = para[2]; connection conn = drivermanager.getconnection(url, usernname, password); //3获取执行sql语句的对象 statement statement = conn.createstatement(); //4获取数据库返回的结果 string sql = "select * from emp"; resultset resultset = statement.executequery(sql); //5处理数据集 try { while (resultset.next()) { //.getxxx方法中的参数 1,字段名 2.字段的下标 int empno = resultset.getint("empno"); string ename = resultset.getstring("ename"); string job = resultset.getstring(3); date date = resultset.getdate(5); system.out.println("empno:" + empno + ", ename:" + ename + ", job:" + job + ", date:" + date); } } catch (exception e) { e.printstacktrace(); } finally { //6关闭连接 resultset.close(); statement.close(); conn.close(); } } }
分层dao
data access object数据访问对象是一个面向对象的数据库接口
会建立一个包:dao,里面的类都是用来操作数据库的。
通常情况下,有几张表,就有几个dao
分层entity、bean、pojo
实体,也就是一个一个类,该类里面只有属性,和对应set.get方法
往往一个表一个实体,实体的属性和表的字段有没有关系,名字一般一样,类型相对应
使用逆向工程,通过表导出实体。
utils 工具类
代替我们去操作一系列的连接关闭等操作
案例:
目录结构如下,
empdao代码如下:
package jdbc.dao; import jdbc.entity.emp; import jdbc.utils.jdbcutils; import java.sql.connection; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; public class empdao { /** * 根据员工id获取员工信息 */ public emp getempbyid(integer id){ connection connection =null; statement statement = null; resultset rs = null; emp emp = null; try { connection = jdbcutils.getconnection(); statement = connection.createstatement(); rs = statement.executequery("select * from emp where empno='"+id+"'"); while (rs.next()){ emp = new emp(); int empno = rs.getint("empno"); emp.setempno(empno); string ename = rs.getstring("ename"); emp.setename(ename); string job = rs.getstring(3); emp.setjob(job); string hiredate = rs.getstring(5); emp.sethiredate(hiredate); } } catch (sqlexception e) { e.printstacktrace(); } finally { jdbcutils.close(connection,statement,rs); } return emp; } public emp getempbyid(string id){ connection connection =null; statement statement = null; resultset rs = null; emp emp = null; try { connection = jdbcutils.getconnection(); statement = connection.createstatement(); rs = statement.executequery("select * from emp where empno="+id); while (rs.next()){ emp = new emp(); int empno = rs.getint("empno"); emp.setempno(empno); string ename = rs.getstring("ename"); emp.setename(ename); string job = rs.getstring(3); emp.setjob(job); string hiredate = rs.getstring(5); emp.sethiredate(hiredate); } } catch (sqlexception e) { e.printstacktrace(); } finally { jdbcutils.close(connection,statement,rs); } return emp; } }
entity中的emp代码如下
package jdbc.entity; public class emp { //emp表中的相关属性 private integer empno; private string ename; private string job; private string mgr; private string hiredate ; private double sal; private double comm; private integer deptno; public integer getempno() { return empno; } public void setempno(integer empno) { this.empno = empno; } public string getename() { return ename; } public void setename(string ename) { this.ename = ename; } public string getjob() { return job; } public void setjob(string job) { this.job = job; } public string getmgr() { return mgr; } public void setmgr(string mgr) { this.mgr = mgr; } public string gethiredate() { return hiredate; } public void sethiredate(string hiredate) { this.hiredate = hiredate; } public double getsal() { return sal; } public void setsal(double sal) { this.sal = sal; } public double getcomm() { return comm; } public void setcomm(double comm) { this.comm = comm; } public integer getdeptno() { return deptno; } public void setdeptno(integer deptno) { this.deptno = deptno; } //默认输出方法 @override public string tostring() { return "emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}'; } }
utils中的jdbcutils代码如下
package jdbc.utils; import java.io.bufferedinputstream; import java.io.fileinputstream; import java.io.ioexception; import java.io.inputstream; import java.sql.*; import java.util.iterator; import java.util.properties; public class jdbcutils { private static final string url ; private static final string username ; private static final string password ; static{ string [] parp = null; try { parp = propread(); } catch (ioexception e) { e.printstacktrace(); } url = parp[0]; username = parp[1]; password=parp[2]; try { class.forname("com.mysql.jdbc.driver"); } catch (classnotfoundexception e) { e.printstacktrace(); } } /** * 创建连接 */ public static connection getconnection() throws sqlexception { connection conn = drivermanager.getconnection(url, username, password); return conn; } public static void close(connection co , statement state, resultset rs){ if(rs != null){ try { rs.close(); } catch (sqlexception e) { e.printstacktrace(); } } if(state !=null){ try { state.close(); } catch (sqlexception e) { e.printstacktrace(); } } if(co !=null){ try { co.close(); } catch (sqlexception e) { e.printstacktrace(); } } } public static void close(connection co , statement state){ if(state !=null){ try { state.close(); } catch (sqlexception e) { e.printstacktrace(); } } if(co !=null){ try { co.close(); } catch (sqlexception e) { e.printstacktrace(); } } } /** * 读取配置文件 * @return * @throws ioexception */ public static string [] propread()throws ioexception { string[] para = new string[3]; int i = 0; properties prop = new properties(); fileinputstream fileinputstream = new fileinputstream("e:\\javalearning\\src\\jdbc\\jdbc.properties"); inputstream in = new bufferedinputstream(fileinputstream); prop.load(in); iterator<string> it = prop.stringpropertynames().iterator(); while (it.hasnext()) { para[i] = prop.getproperty(it.next()); i++; } in.close(); return para; } }
测试代码如下:
package jdbc; import jdbc.dao.empdao; import jdbc.entity.emp; import java.util.scanner; public class main { public static void main(string[] args) { empdao empdao = new empdao(); system.out.println("请输入id"); scanner scanner = new scanner( system.in ); string value = scanner.nextline(); emp emp = empdao.getempbyid (value); emp emp1 = empdao.getempbyid (7900); system.out.println(emp); system.out.println(emp1); } }
这样就简单实现了一个分层的使用jdbc的案例
sql注入攻击
根据上述案例,我们可以输入一个员工的id来查找该员工
但是有一个问题,你如何去规定用户的输入,下面给大家看一个现象
我的数据库在中并没有123456789这个id的人,那么为什么还会有结果呢?
就是因为我们的sql语句是根据字符串拼接生成的,当你输入的数据中包含sql关键字时,会被当成sql语句去执行
注意:这是很危险的!
不友好的用户可以根据这个漏洞对你的数据库进行修改,甚至删除你的数据库!
解决方法:preparedstatement类
preparedstatement是statement的子类
解决原理:
sql语句不在拼接,而是通过预处理,也就是说,用户输入的任何内容,都只能作为值,不解析特殊字符。
修改之后打代码如下:
public emp getempbyid2(string id){ connection connection =null; preparedstatement statement = null; resultset rs = null; emp emp = null; try { connection = jdbcutils.getconnection(); string sql = "select * from emp where empno=?"; statement = connection.preparestatement(sql); statement.setstring(1,id); rs = statement.executequery(); while (rs.next()){ emp = new emp(); int empno = rs.getint("empno"); emp.setempno(empno); string ename = rs.getstring("ename"); emp.setename(ename); string job = rs.getstring(3); emp.setjob(job); string hiredate = rs.getstring(5); emp.sethiredate(hiredate); } } catch (sqlexception e) { e.printstacktrace(); } finally { jdbcutils.close(connection,statement,rs); } return emp; }
再次测试:结果如图
总结:并不是意味着statement不能用,或者不能sql拼接
但是如果是前端穿过的来的值需要直接放到sql语句中,就需要注意。
以上所述是小编给大家介绍的java基础知识——jdbc详解整合,希望对大家有所帮助