赞
踩
一.它是什么?
是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
简单理解为:JDBC,是SUN提供的一套 API,使用这套API可以实现对具体数据库的操作(获取连接、关闭连接、DML、DDL、DCL)
二.为什么要用?
使用它将是为了数据的持久化
数据持久化:将内存中的数据永久的保存在硬盘上,该过程则需要通过各种关系数据库来完成,主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中
三.好处
面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)
面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用
从开发程序员的角度:不需要关注具体的数据库的细节
数据库厂商:只需要提供标准的具体实现。
四.图示理解

五.编写步骤

以下是我使用的版本
@Test public void test1() throws Exception { //获取到输入流 //读取配置的四个信息 //connection.class.getClassLoader()获取类的加载器 = ClassLoader.getSystemClassLoader() // getSystemClassLoader():返回用于委派的系统类加载器 //getResourceAsStream(): 用于读取资源的输入流; null如果找不到该资源,该资源是在一个未被无条件打开的包中,或该资源的访问被安全管理器拒绝。 InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"); //使用Properties获取到其对应信息 Properties pop = new Properties(); //pop从什么里面拿取到 pop.load(inputStream); //设置接收 String user = pop.getProperty("user"); String password = pop.getProperty("password"); //相当于进入网页的链接 jdbc:mysql://localhost:3306/myemployees jdbc:mysql:相当于http localhost:端口号 3306:ip地址 myemployees:需要链接的数据库名 String url = pop.getProperty("url"); //设置驱动 String driverclass = pop.getProperty("driverClass"); //中间其实省略了加载驱动的过程 //{ //DriverManager:用于管理一组JDBC驱动程序的基本服务,初始化完成懒惰,并使用线程上下文类加载器查找服务提供程序。 加载并可用于应用程序的驱动程序将取决于通过,触发驱动程序初始化的线程的线程上下文类加载器。 Class<?> aClass = Class.forName(driverclass); //通过类的暴力反射获取到驱动的对象再强转 Driver driver = (Driver) aClass.newInstance(); //registerDriver(Driver driver):新加载的驱动程序类应该调用方法registerDriver使其自己已知DriverManager 。 如果司机目前已注册,则不采取任何行动。 DriverManager.registerDriver(driver); //} //加载完后就要开始链接 //getConnection(String url, String user, String password):尝试建立与给定数据库URL的连接。 DriverManager尝试从一组已注册的JDBC驱动程序中选择适当的驱动程序。 // url - 表单 jdbc:subprotocol:subname的数据库URL //user - 正在进行连接的数据库用户 //password - 用户密码 Connection connection = DriverManager.getConnection(url, user, password); System.out.println(connection); }
我使用的是maven项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>pro2</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> </dependencies> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> </project>
其配置文件为:

要素介绍:
Driver接口介绍:
加载与注册JDBC驱动:
加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序
URL介绍:
用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
URL的标准由三部分组成,各部分间用冒号分隔。

用户名和密码:
user,password可以用“属性名=属性值”方式告诉数据库
可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接
六.使用PreparedStatement实现CRUD操作
1.简单来说,要实现对数据的CRUD,其根本就是我们java上编写相关语言,数据库接受其命令边反馈其相关语言操作的结果,其实一个数据库连接就是一个Socket连接。
在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

3.PreparedStatement的使用
介绍:PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值
4.PreparedStatement vs Statement
代码的可读性和可维护性;
PreparedStatement 能最大可能提高性能:
DBServer会对预编译语句提供性能优化,固存在预编译的语句会被重复使用,使用PreparedStatement 语句会做到预编译,降低了系统的响应时间,并且会形成缓存,下次再执行的时候就不会都去再匹配一次;
而在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次,使系统响应时间增加,降低了效率。
5.ResultSet与ResultSetMetaData
ResultSet:
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现;
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现;
ResultSetMetaData:
可用于获取关于 ResultSet 对象中列的类型和属性信息的对象

package Connections.Connections; import org.junit.Test; import util.JDBCUtils; import java.lang.reflect.Field; import java.sql.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author BaBa * @Version 1/0 * 操作数据库: * 1.链接 * 2.操作 * (1)传入操作语句(数据库的增删改查语句),这里必须使用占位符代替传入的值 * (2)使用链接的方法prepareStatement(),写入具体操作的sql语句再创建对象 * (3)使用上面创建的对象调用方法setObject(parameterLndex,x) parameterLndex:每列中位置,x:内容 * (4)prepareStatement.execute 提交其数据 * (5)最后释放资源(和io流一样,close()) */ public class connectionTest { //增加 @Test public void Test() { Connection connection = null; PreparedStatement statement = null; try { connection = JDBCUtils.getConnection(); // System.out.println(connection); //5.预编译sql语句,返回PreparedStatemen的实例 String sql = "insert into customers(name,email,date)values(?,?,?)";//?占位符,解决Statement的弊端 statement = connection.prepareStatement(sql); //填充占位符 statement.setString(1, "傻逼"); statement.setString(2, "1314520@qq.com"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd"); Date parse = simpleDateFormat.parse("2001-12-06"); statement.setDate(3, new java.sql.Date(parse.getTime())); // statement.setDate(3,null); statement.execute(); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(connection, statement); } } //修改 @Test public void TsetUpdate() { Connection connection = null; PreparedStatement ps = null; try { //1.获取连接 connection = JDBCUtils.getConnection(); //2.预编译sql语句,返回PreparedStatement的实例 String sql = "update customers set name =? where id =?"; //3.填充占位符 ps = connection.prepareStatement(sql); ps.setObject(1, "周强"); ps.setObject(2, 2); //4.执行 ps.execute(); } catch (Exception e) { e.printStackTrace(); } finally { //5.资源关闭 JDBCUtils.closeResource(connection, ps); } } //通用 public void updateDemo(String sql, Object... args) {//sql中占位符的个数与形参的长度一致 Connection connection = null; PreparedStatement ps = null; try { //获取连接 connection = JDBCUtils.getConnection(); //预编译sql ps = connection.prepareStatement(sql); //填充占位符 for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } //提交 ps.execute(); } catch (Exception e) { e.printStackTrace(); } finally { //释放资源 JDBCUtils.closeResource(connection, ps); } } @Test public void testUpdate() { String sql = "delete from customers where id = ?"; updateDemo(sql, 1); String sql1 = "update users set userid=? where id = ?"; updateDemo(sql1, "王五", 3); } //查找 @Test public void select() { Connection connection = null; PreparedStatement ps = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); String sql = "select id,userid,department_id from users where id = ?"; ps = connection.prepareStatement(sql); ps.setObject(1, 1); //执行并返回结果集 resultSet = ps.executeQuery(); //处理结果集 if (resultSet.next()) {//判断结果集得到下一条有没有数据,如果为true,就往下移动,如果是false,就不往下移 int anInt = resultSet.getInt(1); String string = resultSet.getString(2); int anInt1 = resultSet.getInt(3); Uers uers = new Uers(anInt, string, anInt1); System.out.println(uers); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResourceSelect(connection, ps, resultSet); } } @Test public void test() { String sql = "select id,userid,department_id from users where id < ?"; List<Uers> uers = querUsers(Uers.class, sql, 3); uers.forEach(System.out::println); } // 单个返回值对象 public <T> T querUser(Class<T> tClass, String sql,Object...args) { Connection connection = null; PreparedStatement ps = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); //预编译sql语句 ps = connection.prepareStatement(sql); for (int i=0;i< args.length;i++){ ps.setObject(i+1,args[i]); } //执行查询,返回结果集 resultSet = ps.executeQuery(); //获取结果集的元数据(封装在元数据中) ResultSetMetaData metaData = resultSet.getMetaData(); //通过ResultSetMetaData获取结果集中列数(获取列数) int columnCount = metaData.getColumnCount(); if (resultSet.next()){ T t = tClass.newInstance(); for (int i=0;i<columnCount;i++){ //值 Object values = resultSet.getObject(i + 1); //获取每列的列名 ---不使用 // String catalogName = metaData.getColumnName(i + 1); //表的字段名和类的属性名不相同的情况下: // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名; // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名 //获取列的别名 String label = metaData.getColumnLabel(i + 1); //给Uers对象指定的catalogName属性赋值为values,通过反射 Field field = Uers.class.getDeclaredField(label); field.setAccessible(true); field.set(t,values); } return t; } } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtils.closeResourceSelect(connection,ps,resultSet); } return null; } //多个返回值对象 public <T>List<T> querUsers(Class<T> tClass, String sql, Object... args) { Connection connection = null; PreparedStatement ps = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); //预编译sql语句 ps = connection.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } //执行查询,返回结果集 resultSet = ps.executeQuery(); //获取结果集的元数据(封装在元数据中) ResultSetMetaData metaData = resultSet.getMetaData(); //通过ResultSetMetaData获取结果集中列数(获取列数) int columnCount = metaData.getColumnCount(); //不同于一个返回值对象,这里使用了while,把多个满足条件的放入数组中返回 //创建集合对象 ArrayList<T> list = new ArrayList<T>(); while (resultSet.next()) { T t = tClass.newInstance(); for (int i = 0; i < columnCount; i++) { //值 Object values = resultSet.getObject(i + 1); //获取每列的列名 ---不使用 // String catalogName = metaData.getColumnName(i + 1); //表的字段名和类的属性名不相同的情况下: // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名; // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名 //获取列的别名 String label = metaData.getColumnLabel(i + 1); //给Uers对象指定的catalogName属性赋值为values,通过反射 Field field = Uers.class.getDeclaredField(label); field.setAccessible(true); field.set(t, values); } list.add(t); } return list; } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResourceSelect(connection, ps, resultSet); } return null; } }

注意:使用了反射的技术,通过反射,创建指定类的对象,获取指定的属性并赋值
6.资源的释放
数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。
六.操作BLOB类型字段
1.介绍:MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

注意:
实际使用中根据需要存入的数据大小定义不同的BLOB类型。
需要注意的是:如果存储的文件过大,数据库的性能会下降。
如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。
代码展示:
//插入Blob类型字段
@Test
public void insert() throws Exception {
Connection connection = JDBCUtils.getConnection();
String sql = "insert into customers(name,email,photo) values(?,?,?);";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setObject(1,"王五");
ps.setObject(2,"2751190438@qq.com");
FileInputStream is = new FileInputStream(new File("aa.jpg"));
ps.setBlob(3,is);
ps.execute();
JDBCUtils.closeResource(connection,ps);
}
//查询图片 @Test public void Query() { Connection connection = null; PreparedStatement ps = null; ResultSet rs = null; InputStream is =null; FileOutputStream fos =null; try { connection = JDBCUtils.getConnection(); String sql = "select id,name,email,photo from customers where id =?"; ps = connection.prepareStatement(sql); ps.setObject(1,3); rs = ps.executeQuery(); if (rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); String email = rs.getString(3); //接下来就是把值放到对象中XXX X = new xxx(id,name,email,photo); Blob photo = rs.getBlob(4); //将Blob字段下载下来保存到本地 is = photo.getBinaryStream(); fos = new FileOutputStream("zhangyuhao.jpg"); byte[] bytes = new byte[1024]; int len; while ((len=is.read(bytes))!=-1){ fos.write(bytes,0,len); } } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResourceSelect(connection,ps,rs); try { if (is!=null) is.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fos!=null) fos.close(); } catch (IOException e) { e.printStackTrace(); } } }
七.批量插入
JDBC的批量处理语句包括下面三个方法:
//进阶批量插入 //修改1: 使用 addBatch() / executeBatch() / clearBatch() //修改2:mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。 @Test public void insert3() { Connection connection = null; PreparedStatement ps = null; try { long start = System.currentTimeMillis(); connection = JDBCUtils.getConnection(); //设置不允许自动提交 connection.setAutoCommit(false); String sql = "insert into goods(name)values(?)"; ps = connection.prepareStatement(sql); for (int i=1;i<=100;i++){ ps.setObject(1,"name_"+i); //1.攒sql ps.addBatch(); if (i%10==0){ //2.执行 ps.executeBatch(); //3.清空 ps.clearBatch(); } } //提交 connection.commit(); long end = System.currentTimeMillis(); System.out.println(end-start); } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtils.closeResource(connection,ps); } }
八.事务
1.介绍
一组逻辑操作单元,使数据从一种状态变换到另一种状态。
一组逻辑操作单元:一个或多个DML操作。
2.事务处理的原则:
保证所事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
3.代码体现
考虑到事务以后,实现的通用的增删改操作:
//通用修改 public void update(Connection connection, String sql, Object... args) {//sql中占位符的个数与形参的长度一致 PreparedStatement ps = null; try { //预编译sql ps = connection.prepareStatement(sql); //填充占位符 for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } //提交 ps.execute(); } catch (Exception e) { e.printStackTrace(); } finally { //释放资源 JDBCUtils.closeResource(null, ps); } }
考虑到事务以后,实现的通用的查询:
//通用查询 public <T> T querUser(Connection connection, Class<T> tClass, String sql,Object...args) { PreparedStatement ps = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); //预编译sql语句 ps = connection.prepareStatement(sql); for (int i=0;i< args.length;i++){ ps.setObject(i+1,args[i]); } //执行查询,返回结果集 resultSet = ps.executeQuery(); //获取结果集的元数据(封装在元数据中) ResultSetMetaData metaData = resultSet.getMetaData(); //通过ResultSetMetaData获取结果集中列数(获取列数) int columnCount = metaData.getColumnCount(); if (resultSet.next()){ T t = tClass.newInstance(); for (int i=0;i<columnCount;i++){ //值 Object values = resultSet.getObject(i + 1); //获取每列的列名 ---不使用 // String catalogName = metaData.getColumnName(i + 1); //表的字段名和类的属性名不相同的情况下: // 必须声明sql时,使用类的属性名来命名字段的别名;使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()方法来获取列的别名; // 说明:如果sql中没有给字段起别名,getColumnLabel()获取的就是列名 //获取列的别名 String label = metaData.getColumnLabel(i + 1); //给Uers对象指定的catalogName属性赋值为values,通过反射 Field field = Uers.class.getDeclaredField(label); field.setAccessible(true); field.set(t,values); } return t; } } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtils.closeResourceSelect(null,ps,resultSet); } return null; }
4.属性以及会出现的问题

数据操作过程中可能出现的问题:(针对隔离性)

数据库的四种隔离级别:(一致性和并发性:一致性越好,并发性越差)
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。


如何在Mysql中查看并设置隔离级别:

九.数据库连接池
1.传统连接的问题:

2.如何解决传统开发中的数据库连接问题:使用数据库连接池
3.介绍
数据库连接池的基本思想:- 就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去 。
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
工作原理:

4.使用数据库连接池的好处
资源重用:有需要就从数据库连接池拿出来用,避免了频繁创建,释放连接引起的大量性能开销。
更快的系统反应速度:有备用的链接,初始化的工作已经完成,可以很快速的响应连接。
新的资源分配手段:可以对某一层的连接数量进行限制,避免了某一应用独占所有的数据库资源。
统一的连接管理,避免数据库连接泄漏:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
5.标准接口:DataSource
DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度
6.三种不同的使用连接池情况
C3P0
/**
*
* @Description 使用C3P0的数据库连接池技术
* @author shkstart
* @date 下午3:01:25
* @return
* @throws SQLException
*/
//数据库连接池只需提供一个即可。
private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");
public static Connection getConnection1() throws SQLException{
Connection conn = cpds.getConnection();
return conn;
}
其中,配置文件定义在src下。名为:c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <named-config name="hellc3p0"> <!-- 提供获取连接的4个基本信息 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///test</property> <property name="user">root</property> <property name="password">abc123</property> <!-- 进行数据库连接池管理的基本信息 --> <!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 --> <property name="acquireIncrement">5</property> <!-- c3p0数据库连接池中初始化时的连接数 --> <property name="initialPoolSize">10</property> <!-- c3p0数据库连接池维护的最少连接数 --> <property name="minPoolSize">10</property> <!-- c3p0数据库连接池维护的最多的连接数 --> <property name="maxPoolSize">100</property> <!-- c3p0数据库连接池最多维护的Statement的个数 --> <property name="maxStatements">50</property> <!-- 每个连接中可以最多使用的Statement的个数 --> <property name="maxStatementsPerConnection">2</property> </named-config> </c3p0-config>
DBCP
测试连接的代码:
/** * * @Description 使用DBCP数据库连接池技术获取数据库连接 * @author shkstart * @date 下午3:35:25 * @return * @throws Exception */ //创建一个DBCP数据库连接池 private static DataSource source; static{ try { Properties pros = new Properties(); FileInputStream is = new FileInputStream(new File("src/dbcp.properties")); pros.load(is); source = BasicDataSourceFactory.createDataSource(pros); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection2() throws Exception{ Connection conn = source.getConnection(); return conn; }
其中,配置文件定义在src下:dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=abc123
initialSize=10
Druid
Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。
/** * 使用Druid数据库连接池技术 */ private static DataSource source1; static{ try { Properties pros = new Properties(); InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties"); pros.load(is); source1 = DruidDataSourceFactory.createDataSource(pros); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection3() throws SQLException{ Connection conn = source1.getConnection(); return conn; }
配置文件:
url=jdbc:mysql:///test
username=root
password=abc123
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=10
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。