欢迎访问 生活随笔!

ag凯发k8国际

当前位置: ag凯发k8国际 > 编程资源 > 编程问答 >内容正文

编程问答

jdbc有这一篇就够了(万字jdbc附代码详解) -ag凯发k8国际

发布时间:2024/10/14 编程问答 17 豆豆
ag凯发k8国际 收集整理的这篇文章主要介绍了 jdbc有这一篇就够了(万字jdbc附代码详解) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

目录
1.jdbc的本质
2.jdbc的使用步骤
3.drivermanager对象
4.connectioin对象
5.statement对象
6.resultset对象
7.jdbc工具类
8.preparedstatement类
9.jdbc管理事务

java database connectivity(java语言连接数据库)
jdbc是sun公司制定的一套接口(interface)

第一步:注册驱动(作用:告诉java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示jvm的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行sql语句(dql dml…)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
第六步:释放资源(使用完资源之后一定要关闭资源。java和数据库属于进程间的通信,开启之后一定要关闭。)

代码模版:

package testjdbc;import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement;public class test2 {public static void main(string[] args) throws sqlexception, classnotfoundexception {//1、注册驱动string jdbcdriver = "com.mysql.jdbc.driver";class.forname(jdbcdriver);//2、连接数据库string url="jdbc:mysql://127.0.0.1:3306/school"; //链接数据的urlstring user="root"; //登录数据库的用户名string password="123456"; //用户的密码connection conn = drivermanager.getconnection(url, user, password);statement st = conn.createstatement();//一、查询sqlstring sql="select * from student";resultset rs = st.executequery(sql);system.out.println("sid"" ""sname"" ""sage"" ""ssex");while (rs.next()) {system.out.println(rs.getstring("sid")" "rs.getstring("sname")" "rs.getstring("sage")" "rs.getstring("ssex"));}/*//二、修改数据int update = st.executeupdate("update student set sname='xiaolizi' where sid=2");system.out.println("修改后成功的条数:" update);*///三、删除//st.execute("delete from student where sid='2'");//四、添加数据 // string sql1 = "insert into student(sid,sname,sage,ssex) values('4','郑','3','2')"; // st.execute(sql1);//关闭连接conn.close();st.close();rs.close();} }
3.1drivermanager对象简介

drivermanager是驱动管理对象,有两个功能,第一个功能是注册驱动,第二个功能是获取数据库连接

3.2drivermanager注册驱动

我们查看drivermanager类发现它有这么一个方法

static void registerdriver(driver driver):注册与给定的驱动程序drivermanager

但是我们可以看到我们的注册驱动用到的是
string jdbcdriver ="com.mysql.jdbc.driver";
class.forname(jdbcdriver);
这样的两句代码,那么好像和我们的drivermanager无关。
其实不是,我们写代码使用的是class.forname("com.mysql.jdbc.driver")把driver加载到jvm中,
类里面有静态代码块自动执行

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!");}}}

看到这样的两句代码是不是就恍然大悟,原来在加载这个类的同时执行了同同步代码块,就是在注册驱动

再看下面一张图

我们可以看到这个jar包已经包含了这个驱动加载,如果我们没有写注册驱动,他也会自动加载驱动(也就是说mysql5之后的版本驱动的jar包可以省略注册驱动的步骤)

3.2drivermanager获取数据库连接

方法:

public static connection getconnection(string url,string user,string password)

参数:
*url:指定连接的路径
*语法:jdbc:mysql://ip地址(域名):端口号/数据库名
*例子:jdbc:mysql://localhost:3306/db3
*细节:如果连接的是本机mysql服务器且端口号为3306,可以省略jdbc:mysql:///数据库连接名

connection:数据库连接对象,它的功能有:

1.功能:
获取执行sql的对象
statement createstatement()
preparedstatement preparestatement(string sql)
2.管理事务:
开启事务:setautocommit(boolean autocommit):调用该方法设置参数为false,即开启事务
提交事务:commit();
回滚事务:rollback();

它的作用的执行sql语句,对应的方法有:

(1) boolean execute(string sql):可以执行任意的sql ,不常用(因为他多用于处理相对复杂的sql语句)了解即可
(2) int executeupdate(string sql):执行dml(insert update delete) ddl(create alert drop)语句
返回值:影响的行数,可以通过这个影响的行数判断dml语句是否执行成功
(3)resultset executequery(string sql): 执行dql语句

resultset对象:结果集对象,我们dql查询的结果都在这个对象里,它里边的方法有:

1 . next():游标向下移动一行(如下图游标默认指向id所在行,所以我们需要此方法移动游标)
2 .getxxx(参数):获取数据
xxx代表数据类型 如:int getint(); string getstring();
$参数:
1.int:代表列的编号,从1开始 如:getstring(1);【对应下图id】
2.string代表的是列的名称,如:getdouble(“balance”);

我们获取结果集里边的数据,需要按照如图的方式:

代码模版

while(rs.next()){//6.2获取数据int id=rs.getint(1);//参数可以是数字代表列,可以直接是列名string name=rs.getstring("name");double balance=rs.getdouble(3);system.out.println(id"---"name"---"balance); }

我举个例子,下表打印出来

package cn.itcast.jdbc; import java.sql.*; import java.util.arraylist; import java.util.list; public class jdbc {public static void main(string[] args) {connection conn=null;statement stmt=null;resultset res=null;list<student> list=new arraylist<>();try{class.forname("com.mysql.jdbc.driver");conn= drivermanager.getconnection("jdbc:mysql://localhost:3306/student","root","2332402105");string str="select * from student";stmt=conn.createstatement();res=stmt.executequery(str);while(res.next()){student stu=new student();stu.setname(res.getnstring(1));stu.setage(res.getint(2));stu.setsex(res.getnstring(3));list.add(stu);}}catch(exception e) {e.printstacktrace();}finally {if(conn!=null){try {conn.close();} catch (sqlexception e) {e.printstacktrace();}}if(stmt!=null){try {stmt.close();} catch (sqlexception e) {e.printstacktrace();}}if(res!=null){try {res.close();} catch (sqlexception e) {e.printstacktrace();}}}for (int i = 0; i <list.size() ; i) {system.out.println(list.get(i).getname());system.out.println(list.get(i).getage());system.out.println(list.get(i).getsex());}} } class student{private string name;private int age;private string sex;public string getsex() {return sex;}public void setsex(string sex) {this.sex = sex;}public int getage() {return age;}public void setage(int age) {this.age = age;}public string getname() {return name;}public void setname(string name) {this.name = name;} } 运行结果: 李四 11 男 张三 12 女 翠花 12

刚才我举的例子可以看出来每一次使用jdbc就会有很多重复的代码块(注册驱动释放资源都是重复的代码),jdbc的工具类就是把那么多重复的代码块封装起来变成一个新的类,每次使用的时候就调用这类里的个方法,那么当我们多次使用jdbc的时候就会简便的多,我们把上面的例子拿过来,然后进行改进

我们知道获取连接的时候就是上面例子的这段代码:
conn= drivermanager.getconnection("jdbc:mysql://localhost:3306/student","root","2332402105");,现在们把这段代码包装成一个方法,我们的要求是,方法不允许有参数,还要保证方法的通用性,这时候我们就需要用到我们的配置文件了,里边记录我们获取连接的三个参数,然后把释放资源也包装成一个方法。然后再把我们释放资源封装成一个方法,就有了如下工具类

package jdbctool;import java.io.filereader; import java.io.ioexception; import java.net.url; import java.sql.*; import java.util.properties;public class jdbctool {private static string url;private static string user;private static string password;static { //静态代码块自动读取配置文件到内存try{//创建一个properties集合类properties pro=new properties();//下面三行代码是获取src目录的绝对路径(目的是获取配置文件的路径,但是博主把配置文件放在了src的目录下)classloader classloader=jdbctool.class.getclassloader();url res=classloader.getresource("jdbc.properties");string path=res.getpath();//把读取的配置文件加载进内存pro.load(new filereader(path));//利用类本身的属性获取配置文件里的数据url=pro.getproperty("url");//括号里边的为键名user=pro.getproperty("user");password=pro.getproperty("password");}catch(ioexception e){e.printstacktrace();}}public static connection getconnection() throws sqlexception//获取连接对象{return drivermanager.getconnection(url,user,password);}public static void close(statement stmt,connection conn,resultset res){if(stmt!=null){try {stmt.close();} catch (sqlexception e) {e.printstacktrace();}}if(conn!=null){try {conn.close();} catch (sqlexception e) {e.printstacktrace();}}if(res!=null){try {res.close();} catch (sqlexception e) {e.printstacktrace();}}} }

配置文件里有:
那么每当我们使用jdbc的时获取连接和释放资源都可以使用这个工具类,配置文件的三个参数根据连接的数据库不同适当更改,就会方便很多

8.1登录案例

我们做一个登录案例试试:
我们的student数据库里边有一个表user,然后利用这一个表做一个登录的案例:
user表:

那么我们按照上图的用户名和密码进行登录,代码如下

package login;import java.sql.*; import java.util.scanner;public class login {public boolean login(string username,string password){if(username==null||password==null)return false;connection conn=null;statement stmt=null;resultset res=null;try{class.forname("com.mysql.jdbc.driver");conn= drivermanager.getconnection("jdbc:mysql://localhost:3306/student","root","2332402105");stmt=conn.createstatement();string str="select * from user where name='"username"' and password='"password"'";res = stmt.executequery(str);return res.next();} catch (classnotfoundexception e) {e.printstacktrace();} catch (sqlexception e) {e.printstacktrace();}finally {if(conn!=null){try {conn.close();} catch (sqlexception e) {e.printstacktrace();}}if(stmt!=null){try {stmt.close();} catch (sqlexception e) {e.printstacktrace();}} if(res!=null){try {res.close();} catch (sqlexception e) {e.printstacktrace();}}}return false;}public static void main(string[] args) {scanner p=new scanner(system.in);system.out.println("请输入用户名:");string username=p.next();system.out.println("请输入密码:");string password=p.next();boolean bool=new login().login(username,password);if(bool){system.out.println("登录成功");}else{system.out.println("登录失败");}} }

运行结果:

那么其实这里有一个bug,比如下面的语句查出了所有的用户

我们举一个例子:

我们的表里明明没有这一个user信息为啥会登录成功呢,那么这里就牵扯到我们的sql注入问题

sql注入:在拼接sql语句时有一些sql的特殊关键字参与字符串的拼接,会造成安全性的问题

按照上图输入我们的实际的查询语句是:

当然可以查到用户,而且是相当于查询所有的用户,因为有一个or和一个恒等式

这时候就要用到我们的preparedstatement类,父类是statement

1.statement:执行静态的sql语句,就是直接把我们输入的数据偷换掉sql语句重的username和password,
2.preparedstatement:首先预编译sql语句,参数使用占位符?替换

和statement用法有所不同的是

  • sql参数使用占位符如:"select * from user where name=? and password=?"
  • 需要用preparestatement对象的方法给占位符赋值
  • 在执行sql的时候不需要传递sql语句了,因为在获取preparedstatement对象时候需要传递一个sql语句用于预编译

那么我们按照描述修改例子的代码:

package login;import java.sql.*; import java.util.scanner;public class login {public boolean login(string username,string password){if(username==null||password==null)return false;connection conn=null;preparedstatement pstmt=null;resultset res=null;try{class.forname("com.mysql.jdbc.driver");conn= drivermanager.getconnection("jdbc:mysql://localhost:3306/student","root","2332402105");//定义预编译sql语句strstring str="select * from user where name=? and password=?" ;//获取 preparedstatement对象并且传递预编译sql语句pstmt=conn.preparestatement(str);//set方法给占位符赋值,第一个参数1代表第一个占位符,2代表第二个占位符,第二个参数是赋的值pstmt.setstring(1,username);pstmt.setstring(2,password);res = pstmt.executequery();return res.next();} catch (classnotfoundexception e) {e.printstacktrace();} catch (sqlexception e) {e.printstacktrace();}finally {if(conn!=null){try {conn.close();} catch (sqlexception e) {e.printstacktrace();}}if(pstmt!=null){try {pstmt.close();} catch (sqlexception e) {e.printstacktrace();}} if(res!=null){try {res.close();} catch (sqlexception e) {e.printstacktrace();}}}return false;}public static void main(string[] args) {scanner p=new scanner(system.in);system.out.println("请输入用户名:");string username=p.next();system.out.println("请输入密码:");string password=p.next();boolean bool=new login().login(username,password);if(bool){system.out.println("登录成功");}else{system.out.println("登录失败");}} }


成功解决sql注入问题

在获取到connection对象后,用connection对象方法setautocommit(boolean autocommit):参数为false开启事务
然后整个语句结束后使用connection对象的commit()方法对事务进行提交,我们还可以使用connection对象的rollback()方法对事务进行回滚

总结

以上是ag凯发k8国际为你收集整理的jdbc有这一篇就够了(万字jdbc附代码详解)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得ag凯发k8国际网站内容还不错,欢迎将ag凯发k8国际推荐给好友。

网站地图