2025年jdbc连接数据库步骤代码(jdbc连接数据库流程)

jdbc连接数据库步骤代码(jdbc连接数据库流程)p 背景 p p 前两天一个小伙伴面试的时候 被问 JDBC 底层是如何连接数据库的 p p 他顿时一脸懵逼 因为大部分人只知道 JDBC 的几个步骤 至于底层到底是怎么连接数据库的 还真不知道 p p 由于小伙伴是面试高级开发 问这种问题倒也不能说面试官过分 如果是初级或者中级 p

大家好,我是讯享网,很高兴认识大家。




讯享网

 <p>背景</p><p>前两天一个小伙伴面试的时候,被问JDBC底层是如何连接数据库的?</p><p>他顿时一脸懵逼,因为大部分人只知道JDBC的几个步骤,至于底层到底是怎么连接数据库的,还真不知道。</p><p>由于小伙伴是面试高级开发,问这种问题倒也不能说面试官过分,如果是初级或者中级,那问着问题就确实有些过分了。</p><p>但是如果你在初级或者中级的阶段,就知道了答案,岂不是爽歪歪么?</p><p>估计大部分人都不知道这个问题该怎么回答,稍微发散一下思维,倒是可以猜测一下,今天我们就来搞清楚JDBC底层到底是如何连接数据库的。往后别再猜了。</p><p>反过来,如果面试官问你JDBC的时候,你能知道底层是怎么连接数据库的,估计,很多相对较水的面试官也会一脸懵逼。</p><p>何为 JDBC ?</p><p>JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个</p><p>「规范」</p><p>而不是一个实现,能够执行SQL语句。JDBC由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现,注意:本文中的代码都是针对MySQL数据库实现的。</p><p>JDBC 架构</p><p>分为双层架构和三层架构。</p><p>双层</p><p>作用:此架构中,Java Applet 或应用直接访问数据源。</p><p>条件:要求 Driver 能与访问的数据库交互。</p><p>机制:用户命令传给数据库或其他数据源,随之结果被返回。</p><p>部署:数据源可以在另一台机器上,用户通过网络连接,称为 C/S配置(可以是内联网或互联网)。</p><p>三层</p><p>侧架构特殊之处在于,引入中间层服务。</p><p>流程:命令和结构都会经过该层。</p><p>吸引:可以增加企业数据的访问控制,以及多种类型的更新;另外,也可简化应用的部署,并在多数情况下有性能优势。</p><p>历史趋势:以往,因性能问题,中间层都用 C 或 C++ 编写,随着优化编译器(将 Java 字节码 转为 高效的 特定机器码)和技术的发展,如EJB,Java 开始用于中间层的开发这也让 Java 的优势突显出现出来,使用 Java 作为服务器代码语言,JDBC随之被重视。</p><p>入门案例</p><p>下面给出一个</p><p>JDBC</p><p>入门级案例:</p><p>public</p><p>class</p><p>JdbcDemo</p><p>{</p><p>public</p><p>static</p><p>final</p><p>String URL =</p><p>"jdbc:mysql://localhost:3306/mblog"</p><p>;</p><p>public</p><p>static</p><p>final</p><p>String USER =</p><p>"root"</p><p>;</p><p>public</p><p>static</p><p>final</p><p>String PASSWORD =</p><p>""</p><p>;</p><p>public</p><p>static</p><p>void</p><p>main</p><p>(String[] args)</p><p>throws</p><p>Exception</p><p>{</p><p>Class.forName(</p><p>"com.mysql.jdbc.Driver"</p><p>);</p><p>Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);</p><p>Statement stmt = conn.createStatement();</p><p>ResultSet rs = stmt.executeQuery(</p><p>"SELECT id, name, age FROM m_user where id =1"</p><p>);</p><p>while</p><p>(rs.next()){</p><p>System.out.println(</p><p>"name: "</p><p>+rs.getString(</p><p>"name"</p><p>)+</p><p>" 年龄:"</p><p>+rs.getInt(</p><p>"age"</p><p>));</p><p>}</p><p>}</p><p>}</p><p>JDBC 步骤</p><p>数据库驱动:</p><p>Class.forName(</p><p>"com.mysql.jdbc.Driver"</p><p>);</p><p>获取连接:</p><p>Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);</p><p>创建</p><p>Statement</p><p>或者</p><p>PreparedStatement</p><p>对象:</p><p>Statement stmt = conn.createStatement();</p><p>执行sql数据库查询:</p><p>ResultSet rs = stmt.executeQuery(</p><p>"SELECT id, name, age FROM m_user where id =1"</p><p>);</p><p>解析结果集:</p><p>System.out.println(</p><p>"name: "</p><p>+rs.getString(</p><p>"name"</p><p>)+</p><p>" 年龄:"</p><p>+rs.getInt(</p><p>"age"</p><p>));</p><p>最后就是各种资源的关闭。</p><p>数据库驱动</p><p>加载MySql的驱动类 :</p><p>Class.forName(</p><p>"com.mysql.jdbc.Driver"</p><p>);</p><p>我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道。其实也就是数据库厂商的JDBC接口实现,即对Connection等接口的实现类的jar文件。</p><p>Driver接口</p><p>java.sql.Driver</p><p>此接口是提供给数据库厂商实现的。比如说MySQL的,需要依赖对应的jar包。</p><p>&lt;</p><p>dependency</p><p>&lt;</p><p>groupId</p><p>mysql</p><p>groupId</p><p>&lt;</p><p>artifactId</p><p>mysql-connector-java</p><p>artifactId</p><p>&lt;</p><p>version</p><p>8.0.16</p><p>version</p><p>dependency</p><p>MySQL数据库对应的实现驱动实现类:</p><p>package</p><p>com.mysql.cj.jdbc;</p><p>import</p><p>java.sql.SQLException;</p><p>public</p><p>class</p><p>Driver</p><p>extends</p><p>NonRegisteringDriver</p><p>implements</p><p>java</p><p>.</p><p>sql</p><p>.</p><p>Driver</p><p>{</p><p>static</p><p>{</p><p>try</p><p>{</p><p>//注册驱动</p><p>java.sql.DriverManager.registerDriver(</p><p>new</p><p>Driver());</p><p>}</p><p>catch</p><p>(SQLException E) {</p><p>throw</p><p>new</p><p>RuntimeException(</p><p>"Can't register driver!"</p><p>);</p><p>}</p><p>}</p><p>public</p><p>Driver</p><p>()</p><p>throws</p><p>SQLException</p><p>{</p><p>}</p><p>}</p><p>DriverManager是rt.jar包下的类,(rt=runtime),把我们需要驱动类注册进去。</p><p>//DriverManager类中的方法</p><p>public</p><p>static</p><p>synchronized</p><p>void</p><p>registerDriver</p><p>(java.sql.Driver driver, DriverAction da)</p><p>throws</p><p>SQLException</p><p>{</p><p>/* Register the driver if it has not already been added to our list */</p><p>if</p><p>(driver !=</p><p>null</p><p>) {</p><p>registeredDrivers.addIfAbsent(</p><p>new</p><p>DriverInfo(driver, da));</p><p>}</p><p>else</p><p>{</p><p>// This is for compatibility with the original DriverManager</p><p>throw</p><p>new</p><p>NullPointerException();</p><p>}</p><p>println(</p><p>"registerDriver: "</p><p>+ driver);</p><p>}</p><p>相应装载Oracle驱动:</p><p>Class.forName(</p><p>"oracle.jdbc.driver.OracleDriver"</p><p>);</p><p>Sql Server驱动:</p><p>Class.forName(</p><p>"com.microsoft.jdbc.sqlserver.SQLServerDriver"</p><p>);</p><p>给我们看起来就这一行代码:</p><p>Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);</p><p>下面我们进行深入聊聊这行代码,到底底层是怎么连接数据库的?</p><p>getConnection</p><p>方法三个参数:链接地址,用户名和密码。</p><p>public</p><p>static</p><p>Connection</p><p>getConnection</p><p>(String url,</p><p>String user, String password)</p><p>throws</p><p>SQLException</p><p>{</p><p>java.util.Properties info =</p><p>new</p><p>java.util.Properties();</p><p>if</p><p>(user !=</p><p>null</p><p>) {</p><p>info.put(</p><p>"user"</p><p>, user);</p><p>}</p><p>if</p><p>(password !=</p><p>null</p><p>) {</p><p>info.put(</p><p>"password"</p><p>, password);</p><p>}</p><p>return</p><p>(getConnection(url, info, Reflection.getCallerClass()));</p><p>}</p><p>创建一个Properties对象,Properties是</p><p>HashTable</p><p>的子类。</p><p>public</p><p>class</p><p>Properties</p><p>extends</p><p>Hashtable</p><p>&lt;</p><p>Object</p><p>,</p><p>Object</p><p>{</p><p>//.....</p><p>}</p><p>再看</p><p>getConnection</p><p>方法:</p><p>// Worker method called by the public getConnection() methods.</p><p>private</p><p>static</p><p>Connection</p><p>getConnection</p><p>(</p><p>String url, java.util.Properties info, Class caller)</p><p>throws</p><p>SQLException</p><p>{</p><p>ClassLoader callerCL = caller !=</p><p>null</p><p>? caller.getClassLoader() :</p><p>null</p><p>;</p><p>SQLException reason =</p><p>null</p><p>;</p><p>//遍历气门注册的数据库驱动</p><p>for</p><p>(DriverInfo aDriver : registeredDrivers) {</p><p>try</p><p>{</p><p>//获取连接</p><p>Connection con = aDriver.driver.connect(url, info);</p><p>if</p><p>(con !=</p><p>null</p><p>) {</p><p>// Success!</p><p>println(</p><p>"getConnection returning "</p><p>+ aDriver.driver.getClass().getName());</p><p>return</p><p>(con);</p><p>}</p><p>}</p><p>catch</p><p>(SQLException ex) {</p><p>if</p><p>(reason ==</p><p>null</p><p>) {</p><p>reason = ex;</p><p>}</p><p>}</p><p>}</p><p>}</p><p>这段代码的关键是这一句代码:</p><p>Connection con = aDriver.driver.connect(url, info);</p><p>connet()</p><p>方法是每个数据库驱动自己的实现的。</p><p>package</p><p>com.mysql.cj.jdbc;</p><p>public</p><p>class</p><p>NonRegisteringDriver</p><p>implements</p><p>java</p><p>.</p><p>sql</p><p>.</p><p>Driver</p><p>{</p><p>@Override</p><p>public</p><p>java.sql.</p><p>Connection</p><p>connect</p><p>(String url, Properties info)</p><p>throws</p><p>SQLException</p><p>{</p><p>//部分无关键要的代码省略</p><p>//下面是重点</p><p>ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);</p><p>switch</p><p>(conStr.getType()) {</p><p>//SINGLE_CONNECTION("jdbc:mysql:", HostsCardinality.SINGLE), //</p><p>case</p><p>SINGLE_CONNECTION:</p><p>return</p><p>com.mysql.cj.jdbc.ConnectionImpl.getInstance(conStr.getMainHost());</p><p>case</p><p>LOADBALANCE_CONNECTION:</p><p>return</p><p>LoadBalancedConnectionProxy.createProxyInstance((LoadbalanceConnectionUrl) conStr);</p><p>case</p><p>FAILOVER_CONNECTION:</p><p>return</p><p>FailoverConnectionProxy.createProxyInstance(conStr);</p><p>case</p><p>REPLICATION_CONNECTION:</p><p>return</p><p>ReplicationConnectionProxy.createProxyInstance((ReplicationConnectionUrl) conStr);</p><p>default</p><p>:</p><p>return</p><p>null</p><p>;</p><p>}</p><p>}</p><p>}</p><p>ConnectionUrl从这个类名应该能猜到还不到真正连接的,只是创建一个连接Url相关信息封装。</p><p>public</p><p>abstract</p><p>class</p><p>ConnectionUrl</p><p>implements</p><p>DatabaseUrlContainer</p><p>{</p><p>private</p><p>static</p><p>final</p><p>String DEFAULT_HOST =</p><p>"localhost"</p><p>;</p><p>private</p><p>static</p><p>final</p><p>int</p><p>DEFAULT_PORT =</p><p>3306</p><p>;</p><p>//...</p><p>}</p><p>熟悉的身影,MySQL数据库默认端口。我们继续看下一行重要的代码:</p><p>ConnectionImpl.getInstance(conStr.getMainHost());</p><p>这里就是获取一个实例,不出意外,连接就在这里面产生的。继续:</p><p>//ConnectionImpl</p><p>public</p><p>static</p><p>JdbcConnection</p><p>getInstance</p><p>(HostInfo hostInfo)</p><p>throws</p><p>SQLException</p><p>{</p><p>return</p><p>new</p><p>ConnectionImpl(hostInfo);</p><p>}</p><p>ConnectionImpl构造方法里有调用createNewIO方法:</p><p>@Override</p><p>public</p><p>void</p><p>createNewIO</p><p>(</p><p>boolean</p><p>isForReconnect)</p><p>{</p><p>synchronized</p><p>(getConnectionMutex()) {</p><p>try</p><p>{</p><p>if</p><p>(!</p><p>this</p><p>.autoReconnect.getValue()) {</p><p>connectOneTryOnly(isForReconnect);</p><p>return</p><p>;</p><p>}</p><p>connectWithRetries(isForReconnect);</p><p>}</p><p>catch</p><p>(SQLException ex) {</p><p>}</p><p>}</p><p>}</p><p>private</p><p>void</p><p>connectOneTryOnly</p><p>(</p><p>boolean</p><p>isForReconnect)</p><p>throws</p><p>SQLException</p><p>{</p><p>Exception connectionNotEstablishedBecause =</p><p>null</p><p>;</p><p>JdbcConnection c = getProxy();</p><p>//又看到熟悉的connet方法,</p><p>this</p><p>.session.connect(</p><p>this</p><p>.origHostInfo,</p><p>this</p><p>.user,</p><p>this</p><p>.password,</p><p>this</p><p>.database, DriverManager.getLoginTimeout() *</p><p>1000</p><p>, c);</p><p>this</p><p>.session.setQueryInterceptors(</p><p>this</p><p>.queryInterceptors);</p><p>}</p><p>其中,这里的session是NativeSession。</p><p>public</p><p>void</p><p>connect</p><p>(HostInfo hi, String user, String password, String database,</p><p>int</p><p>loginTimeout, TransactionEventHandler transactionManager)</p><p>throws</p><p>IOException</p><p>{</p><p>SocketConnection socketConnection =</p><p>new</p><p>NativeSocketConnection();</p><p>socketConnection.connect(</p><p>this</p><p>.hostInfo.getHost(),</p><p>this</p><p>.hostInfo.getPort(),</p><p>this</p><p>.propertySet, getExceptionInterceptor(),</p><p>this</p><p>.log, loginTimeout);</p><p>this</p><p>.protocol.connect(user, password, database);</p><p>this</p><p>.protocol.getServerSession().setErrorMessageEncoding(</p><p>this</p><p>.protocol.getAuthenticationProvider().getEncodingForHandshake());</p><p>}</p><p>在这个方法里,我们看到了Socket的命名开头的类,哈哈,是不是就是使用Socket进行通信的呢?</p><p>精彩继续:</p><p>socketConnection.connect(</p><p>this</p><p>.hostInfo.getHost(),</p><p>this</p><p>.hostInfo.getPort(), ...);</p><p>来到NativeSocketConnection类中方法:</p><p>//com.mysql.cj.protocol.a.NativeSocketConnection</p><p>@Override</p><p>public</p><p>void</p><p>connect</p><p>(String hostName,</p><p>int</p><p>portNumber, PropertySet propSet, ExceptionInterceptor excInterceptor, Log log,</p><p>int</p><p>loginTimeout)</p><p>{</p><p>this</p><p>.mysqlSocket =</p><p>this</p><p>.socketFactory.connect(</p><p>this</p><p>.host,</p><p>this</p><p>.port, propSet, loginTimeout);</p><p>//...</p><p>}</p><p>这里的socketFactory是StandardSocketFactory。所以也就是调用的是StandardSocketFactory的connect方法:</p><p>//StandardSocketFactory</p><p>public</p><p>T</p><p>connect</p><p>(String hostname,</p><p>int</p><p>portNumber, PropertySet pset,</p><p>int</p><p>loginTimeout)</p><p>throws</p><p>IOException</p><p>{</p><p>this</p><p>.rawSocket = createSocket(pset);</p><p>this</p><p>.rawSocket.connect(sockAddr, getRealTimeout(connectTimeout));</p><p>}</p><p>protected</p><p>Socket</p><p>createSocket</p><p>(PropertySet props)</p><p>{</p><p>return</p><p>new</p><p>Socket();</p><p>}</p><p>这里就算到底了,说白</p><p>JDBC</p><p>的底层就是使用</p><p>「Socket」</p><p>进行连接数据库的。</p><p>常用方法</p><p>方法</p><p>描述</p><p>createStatement()</p><p>创建向数据库发送sql的statement对象。</p><p>prepareStatement(sql)</p><p>创建向数据库发送预编译sql的PrepareSatement对象。</p><p>prepareCall(sql)</p><p>创建执行存储过程的callableStatement对象。</p><p>setAutoCommit(boolean autoCommit)</p><p>设置事务是否自动提交。</p><p>commit()</p><p>在链接上提交事务。</p><p>rollback()</p><p>在此链接上回滚事务。</p><p>获取Statement</p><p>三种类型</p><p>要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3 种类型:</p><p>执行静态SQL语句。通常通过Statement实例实现。</p><p>执行动态SQL语句。通常通过PreparedStatement实例实现。</p><p>执行数据库存储过程。通常通过CallableStatement实例实现。</p><p>具体获取方式</p><p>Statement stmt = con.createStatement() ;</p><p>PreparedStatement pstmt = con.prepareStatement(sql) ;</p><p>CallableStatement cstmt = con.prepareCall(</p><p>"{CALL demoSp(? , ?)}"</p><p>) ;</p><p>常用方法</p><p>方法</p><p>含义</p><p>executeQuery(String sql)</p><p>用于向数据发送查询语句。</p><p>executeUpdate(String sql)</p><p>用于向数据库发送insert、update或delete语句</p><p>execute(String sql)</p><p>用于向数据库发送任意sql语句</p><p>addBatch(String sql)</p><p>把多条sql语句放到一个批处理中。</p><p>executeBatch()</p><p>向数据库发送一批sql语句执行。</p><p>Statement和PreparedStatement的异同及优缺点</p><p>同:两者都是用来执SQL语句的</p><p>异:PreparedStatement需要根据SQL语句来创建,它能够通过设置参数,指定相应的值,不是像Statement那样使用字符串拼接的方式。</p><p>PreparedStatement的优点:</p><p>1、其使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差。</p><p>2、其具有预编译机制,性能比statement更快。</p><p>3、其能够有效防止SQL注入攻击。</p><p>execute和executeUpdate的区别</p><p>相同点:二者都能够执行增加、删除、修改等操作。</p><p>不同点:</p><p>1、execute可以执行查询语句,然后通过getResult把结果取出来。executeUpdate不能执行查询语句。</p><p>2、execute返回Boolean类型,true表示执行的是查询语句,false表示执行的insert、delete、update等。executeUpdate的返回值是int,表示有多少条数据受到了影响。</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2FoPUoNLo8pLJXwXaI5UtVutD8TMLE9WNfqDMndzkH3Pogh55.jpeg&thumbnail=660x&quality=80&type=jpg"/><br/></p> 

讯享网
小讯
上一篇 2025-06-14 09:56
下一篇 2025-06-12 07:30

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/182626.html