Table of Contents

1:概述

 2:准备工作

 3:Java连接postgreSQL代码示例。

 3:PreparedStatement与Statement的区别

 4:代码分析在上述对数据库进行增删改查的过程中,可以发现其共性部分,即通用的流程:

 5:JDBC的API

5.1:JDBC对于存储过程的访问

 6:JDBC的一般工作流程

(6.1)加载驱动

(6.2)建立连接

(6.3)获得Statement对象

(6.4)执行sql语句

(6.5)处理结果集

(6.6)关闭数据库连接

 7:JDBC事务

(7.1) 原子性

(7.2) 一致性

(7.3) 分离性

(7.4) 持久性

8: 数据库连接池技术

8.1:C3P0数据库连接池技术

8.2:Druid数据库连接池技术


1:概述

本文借postgreSQL通过JDBC连接数据库的示例,介绍了常见数据库操作及JDBC的API、JDBC的一般工作流程及JDBC事务。

pgJDBC驱动可以使Java程序以标准的数据库无关的java代码连接pg。除了一些pg特定的是纯java实现,因此只需要下载jar包就可以开干了。

扩展PostgreSQL的外,该驱动程序提供了相当完整的JDBC3规范的实施。目标是完全符兼容,但现在还没有兼容在todo list中列出

 2:准备工作


A、下载安装好postgreSQL数据库。

B、新建一个java项目,并导入postgreSQL的JDBC驱动程序jar包(http://jdbc.postgresql.org/

 3:Java连接postgreSQL代码示例。

package weavernoth.wkl.action;



import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * Description:PostgreSQL的jdbc
 * Date:       2020/4/28 - 上午 11:18
 * author:    
 * version:    V1.0
 */
public class JdbcCronJob  {
    @Override
    public void execute() {
       
        String url = "jdbc:postgresql://locahost:5432/test_db";

        String usr = "root";

        String psd = "123456";


        Connection conn = null;

        try {

            Class.forName("org.postgresql.Driver");

            conn = DriverManager.getConnection(url, usr, psd);

            Statement st = conn.createStatement();
//Statement:适合只执行一次或极少执行的sql文。

//PreparedStatement:适合执行需要传参并且会多次执行的sql文,并且一定程度上防止了sql注入。

//CallableStatement:适合执行存储过程。

            ResultSet rs = st.executeQuery("select id,name from tablename");

            while (rs.next()) {
                System.ouy.print(rs.getString(1));
                System.ouy.print(rs.getString(2));
                
            }

            rs.close();

            st.close();

            conn.close();

        } catch (Exception e) {
            System.ouy.print(e);
            e.printStackTrace();

        }


    }
}

 3:PreparedStatement与Statement的区别

1:JDBC中执行sql对表的查询有三种方式,静态SQL语句(Statement),动态SQL语句(PreparedStatement),与存储过程(CallableStatement)三种方式,

2:java.sql包中的PreparedStatement 接口继承了Statement,并与之在两方面有所不同:有人主张,在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替Statement.也就是说,在任何时候都不要使用Statement。

3:public interface PreparedStatement extends Statement;可以看到PreparedStatement是Statement的子接口,我们在执行查询或者更新数据表数据的时候,拼写SQL语句是一个很费力并且容易出错的事情,PreparedStatement可以简化这样的一个过程.

4:使用Statement需要进行拼写SQl语句,辛苦并且容易出错,之前使用Statement的SQL语句的形式是这样的
 

 Class.forName("org.postgresql.Driver");

            conn = DriverManager.getConnection(url, usr, psd);

            Statement st = conn.createStatement();

            ResultSet rs = st.executeQuery("select id,name from tablemame where id = 1");

            while (rs.next()) {
                rs.getString(1));
                rs.getString(2));
            }

            rs.close();

            st.close();

            conn.close();

5:使用PreparedStatement:是Statement的子接口,可以传入带占位符的SQL语句,提供了补充占位符变量的方法

PreparedStatement的特点

      PreparedStatemant,是处理预编译语句的一个接口,PreparedStatemant可用于执行动态的SQL语句,所谓动态SQL语句,就是可以在SQL语句中提供参数,这是我们可以对相同的SQL语句替换参数从而多次使用。因此当一个SQL语句需要执行多次时,使用预编译语句可以减少执行时间。

String sql = "select id,name from tablename where id = ?";
            PreparedStatement perstmt=conn.prepareStatement(sql);
            //注入参数
            perstmt.setInt(1,1);
            ResultSet rs = perstmt.executeQuery();
            while (rs.next()) {
               rs.getString(1));
               rs.getString(2));
            }

            rs.close();

            perstmt.close();

            conn.close();



 

 

 4:代码分析
在上述对数据库进行增删改查的过程中,可以发现其共性部分,即通用的流程:

 

(1)创建Connection对象、SQL查询命令字符串;

 

(2)对Connection对象传入SQL查询命令,获得PreparedStatement对象;

 

(3)对PreparedStatement对象执行executeUpdate()或executeQurey()获得结果;

 

(4)先后关闭PreparedStatement对象和Connection对象。

 

可见,使用JDBC时,最常打交道的是Connection、PreparedStatement这两个类,以及select中的ResultSet类。


 5:JDBC的API

Statement:适合只执行一次或极少执行的sql文。

PreparedStatement:适合执行需要传参并且会多次执行的sql文,并且一定程度上防止了sql注入。

CallableStatement:适合执行存储过程。

5.1:JDBC对于存储过程的访问

以上两种语法中,对于ORACLE来说,前者用于函数调用,后者用于存储过程调用;       在以上访问中,返回值类型和输出类型的参数一样处理;输入类型的参数另外处理;不过对于大多数的数据库产品,在JDBC中,都不能访问函数;

实例:

创建一个存储过程,传递emp表中的一个empno,返回员工的姓名和薪水;

create or replace procedure getinfo(id in emp.empno%type,
		name out emp.ename%type,salary out emp.sal%type)
is
begin
	select ename,sal into name,salary from emp where empno=id;
end;

java代码:

package com.javakc.jdbc.sql.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import com.javakc.jdbc.sql.utils.Db;
import oracle.jdbc.internal.OracleTypes;
public final class MyApp {
	public final static void main(String[] args) {
		Connection conn = Db.getConnection();
		CallableStatement cstmt = null;
		try {
             //创建一个调用数据库存储过程的 CallableStatement对象
			cstmt = conn.prepareCall("{call getinfo(?,?,?)}");
            //这两个是返回的值,注册的时候先占位
			cstmt.registerOutParameter(2, OracleTypes.VARCHAR);
			cstmt.registerOutParameter(3, OracleTypes.NUMBER);
			cstmt.setObject(1, 7788);
            //执行
			cstmt.execute();
			System.out.println("姓名: " + cstmt.getObject(2));
			System.out.println("薪水: " + cstmt.getObject(3));
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			Db.close(cstmt, conn);
		}
	}
}

 

 6:JDBC的一般工作流程

 

(6.1)加载驱动


        

 Class.forName(“org.postgresql.Driver”); 

        JAVA规范中明确规定:所有的驱动程序必须在静态初始化代码块中将驱动注册到驱动程序管理器中。

(6.2)建立连接

conn=DriverManager.getConnection("jdbc:postgresql://localhost:5432/pgsqltest","postgres", "2016");

Connection连接是通过DriverManager的静态方法getConnection(.....)来得到的,这个方法的实质是把参数传到实际的Driver中的connect()方法中来获得数据库连接的。

postgreSQL URL的格式:jdbc:postgresql:(协议)@XXX.XXX.X.XXX:XXXX(IP地址及端口号):XXXXXXX(所使用的库名)

MySql URL的写法 例:jdbc:mysql://192.168.8.21:3306/test

(6.3)获得Statement对象

Statement stmt = conn.createStatement();

(6.4)执行sql语句


stmt.executeQuery(String sql); //返回一个查询结果集。

stmt.executeUpdate(String sql); //返回值为int型,表示影响记录的条数。

将sql语句通过连接发送到数据库中执行,以实现对数据库的操作。

(6.5)处理结果集


使用Connection对象获得一个Statement,Statement中的executeQuery(Stringsql) 方法可以使用select语句查询,并且返回一个结果集。 ResultSet,通过遍历这个结果集,可以获得select语句的查寻结果,ResultSet的next()方法会操作一个游标从第一条记录的前面开始读取,直到最后一条记录。

executeUpdate(String sql) 方法用于执行DDL和DML语句,比如可以update,delete操作。

只有执行select语句才有结果集返回。

Statement str=con.createStatement(); //创建Statement

String sql=”insert into test(id,name)values(1,”+”’”+”test”+”’”+”)”;

str. executeUpdate(sql);//执行Sql语句

String sql=”select * from test”;

ResultSet rs=str. executeQuery(String sql);//执行Sql语句,执行select语句后有结果集

//遍历处理结果集信息

while(rs.next()){

System.out.println(rs.getInt(“id”));

System.out.println(rs.getString(“name”))

}

(6.6)关闭数据库连接


rs.close();

stmt.close();

con.close();

ResultSet Statement Connection是依次依赖的。

 7:JDBC事务

事务的4大特性

(7.1) 原子性

事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据修改操作要么全部执行,要么完全不执行。

原子操作,也就是不可分割的操作,必须一起成功一起失败。

(7.2) 一致性

事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。

(7.3) 分离性

分离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。

(7.4) 持久性

持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。即一旦一个事务提交,DBMS保证它对数据库中数据的改变应该是永久性的,耐得住任何系统故障。持久性通过数据库备份和恢复来保证。


代码:

8: 数据库连接池技术

Datasource   javax.sql包下的,由数据库厂商了实现

c3p0:老牌数据库连接池技术

Druid:德鲁伊---阿里巴巴的数据库连接池技术

注:用了连接池后,connoction.close()关闭,只是将数据库中的链接归还了,而不是关闭了

8.1:C3P0数据库连接池技术

步骤:

1:导包:我的是mysql8,所以用这个包,要是包不对,会错

2:配置文件:

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test?useSSL=false&amp;serverTimezone=Hongkong&amp;characterEncoding=utf-8&amp;autoReconnect=true</property>
    <property name="user">root</property>
    <property name="password">123456</property>
    
    <!-- 连接池参数 -->
    <!--初始连接数-->
    <property name="initialPoolSize">5</property>
    <!--最大连接数-->
    <property name="maxPoolSize">10</property>
    <!--超时时间-->
    <property name="checkoutTimeout">3000</property>
  </default-config>

  <named-config name="otherc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>

3:测试

@Test
    public void test01() throws SQLException {
        DataSource ds = new ComboPooledDataSource();

        Connection connection = ds.getConnection();

        System.out.println(""+connection);//com.mchange.v2.c3p0.impl.NewProxyConnection@13fee20c
    }

或者是这样

 @Test
    public void test02() throws SQLException, PropertyVetoException {

        ComboPooledDataSource ds  = new ComboPooledDataSource();
        //这里用的是properties文件
        ResourceBundle rb = ResourceBundle.getBundle("c3p0");
        ds.setDriverClass(rb.getString("driverClass"));
        ds.setJdbcUrl(rb.getString("url"));
        ds.setUser(rb.getString("username"));
        ds.setPassword(rb.getString("password"));
        ds.setInitialPoolSize(Integer.parseInt(rb.getString("initialSize")));
        ds.setMaxPoolSize(Integer.parseInt(rb.getString("maxActive")));
        ds.setCheckoutTimeout(Integer.parseInt(rb.getString("maxWait")));

        Connection conn=ds.getConnection();
    }

8.2:Druid数据库连接池技术

步骤:

1:导包:druid-1.1.9  和数据库驱动包

2:配置文件,可放在任意位置:properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///ManageSys
username=root
password=admin123
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

3:利用工厂创建连接

@Test
    public void test01() throws Exception {

        Properties properties = new Properties();
        //通过类加载器找到文件路径,读配置文件
        InputStream inputStream = DruidDemo.class.getResourceAsStream("/d.properties");
        properties.load(inputStream);
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        Connection connection = dataSource.getConnection();
    }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐