jdbc学习记录

jdbc学习记录

一:JDBC应用

JDBC主要能分为几个步骤,分别是初始化驱动,建立数据库的连接,创建statement,执行sql语句,关闭连接。

 

初始化驱动:

通过Class.forName("com.mysql.jdbc.Driver"); 初始化驱动类.Class.forName是加载这个类到JVM中,加载的时候就会执行其中的静态初始化快,完成驱动的初始化相关工作。

jdbc学习记录

向java.sql.DriverManager注册自身,注册驱动首先就是初始化。

jdbc学习记录

然后封装信息到DriverInfo中,最后成为驱动集合的一部分。

可以看到jdbc 的驱动类Driver实际上实现了java.sql.Driver

jdbc学习记录

任何驱动类都需要实现这个接口。在DriverManager类中使用的都是Driver类。也就是说使用驱动不会涉及具体的实现。

不管使用何种数据库,只需要更换参数即可。

从网上找到一个注册驱动的具体过程序列图如下:

jdbc学习记录

建立数据库的连接:

数据库连接的底层是客户端与mysql服务器建立了TCP长连接。

Connection c = DriverManager

                    .getConnection(

                            "jdbc:mysql://127.0.0.1:3306/hellow?characterEncoding=UTF-8",

                            "root""admin");

 

建立与数据库的连接,需要提供数据库所在ip 127.0.0.1,数据库端口号port 3306,数据库名称db hellow,编码方式 UTF-8

数据库账号 root,数据库密码 admin。(视个人情况而定)

jdbc学习记录

jdbc学习记录

getConnection:

jdbc学习记录

从driverManager可以看出调用getConnection时,会根据初始化加载的驱动Driver来查找合适的驱动程序。

最后通过com.mysql.jdbc.Driver.connect建立连接。

jdbc学习记录

通过com.jdbc.mysql.ConnectionImpl建立连接。

jdbc学习记录

jdbc学习记录

接着跟代码

可以发现this.connectOneTryOnly(xx); this.connectWithRetries(xx);中都用到了coreConnect(xxx) 方法。这就是连接的核心:

jdbc学习记录jdbc学习记录

上图红圈中分别会做两件事:与MysqlServer建立Socket连接。连接成功后将参数账号,密码,数据库名等发送并进行登录校检。。

jdbc学习记录

 

最后依旧是以网上一张具体的获取数据库连接的序列图结尾:

jdbc学习记录

创建statement:

Statement s = c.createStatement();

注意是java.sql.Statement 而不是 com.mysql.jdbc.Statement

c是上一步创建的Connection对象

jdbc学习记录

jdbc学习记录

这个比较简单,即通过刚刚建立的Connection类来获取执行sql语句并存储返回结果的对象。

这里要特别提及另外一种PreparedStatement方式。

创建预编译PreparedStatement

String sql = "insert into user values(null,?,?,?)";

PreparedStatement ps = c.prepareStatement(sql);

和Statement一样,PreparedStatement也是用来执行sql语句的,但是与Statement不一样的是,需要先创建sql语句,再根据sql语句来创建PreparedStatement。除此之外,还能够通过设置参数,而不是像Statement那样拼接字符串。

注意:JAVA里面有两个基为1的地方,一个是这里,还有一个是查询语句中的ResultSet也是基1的。

PreparedStatetment与Statement相比,PreparedStatement有三个好处。

第一个是刚刚提及的设置参数,而不用在写sql时就将参数都确定。

第二个是有预编译机制,性能比Statement更快。

第三个是防止SQL注入攻击。 

补充:SQL注入就是在url或者页面上查询或插入时,插入SQL语句,最终使服务器执行恶意的SQL命令,比如select * from user where name = ?。 当参数 ? 为 xiaoming,最多返回符合名字为xiaoming的数据,但是如果参数 ? 为 xiaoming or 1=1 时,将会返回所有的数据,当user表数据量达到上百万时,甚至可能让服务器瘫痪。而PreparedStatement则会规定好SQL语句的格式,需要查的数据也设置好了,缺的只是那几个参数,而不会额外执行恶意添加的语句(or 1=1 或者 ; delete * from user )

 

jdbc学习记录

执行sql语句:

当创建好Statement或者PreparedStatement之后,就可以通过execute()或者executeQuery()来执行了。

Statement与PreparedStatement不同,PreparedStatement是根据SQL预编译后的模板,加上设置的参数,解析成一条完整的语句,而Statement则是直接编译和执行整条完整的语句。最后都根据MySql协议,序列化成字节流,RPC发送给MySql服务端。

1.  public java.sql.ResultSet executeQuery() throws SQLException {  

2.      checkClosed();  

3.      ConnectionImpl locallyScopedConn = this.connection;  

4.      CachedResultSetMetaData cachedMetadata = null;  

5.      synchronized (locallyScopedConn.getMutex()) {  

6.          if (doStreaming  

7.                  && this.connection.getNetTimeoutForStreamingResults() > 0) {  

8.              locallyScopedConn.execSQL(this, "SET net_write_timeout="  

9.                      + this.connection.getNetTimeoutForStreamingResults(),  

10.                     -1, null, ResultSet.TYPE_FORWARD_ONLY,  

11.                     ResultSet.CONCUR_READ_ONLY, falsethis.currentCatalog,  

12.                     nullfalse);  

13.         }  

14.         //解析封装需要发送的sql语句,序列化成MySQL协议对应的字节流            

15.         Buffer sendPacket = fillSendPacket();   

17.         if (locallyScopedConn.getCacheResultSetMetadata()) {  

18.             cachedMetadata = locallyScopedConn.getCachedMetaData(this.originalSql);  

19.         }  

21.         Field[] metadataFromCache = null;  

23.            // 执行sql语句,并获取MySQL发送过来的结果字节流,根据MySQL协议反序列化成ResultSet
 

24.            this.results = executeInternal(-1, sendPacket,  

25.                     doStreaming, true,  

26.                     metadataFromCache, false);

27.   

28.         if (oldCatalog != null) {  

29.             locallyScopedConn.setCatalog(oldCatalog);  

30.         }  

32.     }  

33.     this.lastInsertId = this.results.getUpdateID();  

34.     return this.results;  

35. }  

关闭连接:

            // 先关闭Statement

            if (s != null)

                try {

                    s.close();

                catch (SQLException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

            // 后关闭Connection

            if (c != null)

                try {

                    c.close();

                catch (SQLException e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

也可以使用try-with-resource的方式自动关闭连接。因为Connection和Statement都实现了AutoCloseable接口。

jdbc学习记录

注意这是jdk1.7之后才有的特性

jdbc学习记录

相关文章:

  • 2022-01-18
  • 2021-09-04
  • 2021-07-07
  • 2021-08-21
  • 2021-06-05
  • 2021-08-27
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2023-01-14
  • 2022-01-04
  • 2021-05-30
相关资源
相似解决方案