数据库-JDBC、数据库连接池与DBUtils

JDBC

数据库与Java程序连接的”桥梁”,用法:

  1. 首先给项目导入jar包connectorJ

  2. 然后开始编写代码(数据库需要事先准备好,确保数据库服务打开)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    //STEP 1. Import required packages
    import java.sql.*;

    public class FirstExample {
    // JDBC driver name and database URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3306/EMP";

    // Database credentials
    static final String USER = "username";
    static final String PASS = "password";

    public static void main(String[] args) {
    Connection conn = null;
    Statement stmt = null;
    try{
    //STEP 2: Register JDBC driver
    Class.forName("com.mysql.jdbc.Driver");

    //STEP 3: Open a connection
    System.out.println("Connecting to database...");
    conn = DriverManager.getConnection(DB_URL,USER,PASS);

    //STEP 4: Execute a query
    System.out.println("Creating statement...");
    stmt = conn.createStatement();
    String sql;
    sql = "SELECT id, first, last, age FROM Employees";
    ResultSet rs = stmt.executeQuery(sql);

    //STEP 5: Extract data from result set
    while(rs.next()){
    //Retrieve by column name
    int id = rs.getInt("id");
    int age = rs.getInt("age");
    String first = rs.getString("first");
    String last = rs.getString("last");

    //Display values
    System.out.print("ID: " + id);
    System.out.print(", Age: " + age);
    System.out.print(", First: " + first);
    System.out.println(", Last: " + last);
    }
    //STEP 6: Clean-up environment
    rs.close();
    stmt.close();
    conn.close();
    }catch(SQLException se){
    //Handle errors for JDBC
    se.printStackTrace();
    }catch(Exception e){
    //Handle errors for Class.forName
    e.printStackTrace();
    }finally{
    //finally block used to close resources
    try{
    if(stmt!=null)
    stmt.close();
    }catch(SQLException se2){
    }// nothing we can do
    try{
    if(conn!=null)
    conn.close();
    }catch(SQLException se){
    se.printStackTrace();
    }//end finally try
    }//end try
    System.out.println("Goodbye!");
    }//end main
    }//end FirstExample

    上述代码表示了,使用jdbc连接了一个,用户名为username,密码为password,数据库链接为:jdbc:mysql://localhost:3306/EMP的一个mysql数据库.然后查询EMP表中的id,age,first,last字段.

  3. 点击运行查看效果,注意: 确保数据库url正确,用户名密码正确,jar包引入正确,数据库中存在要查询的表和字段,查询完成后及时关闭资源.

加入事务

对于如同转账类似的数据库操作,需要删除和添加两步操作,如果一步操作完成后,程序发生了错误,就会导致第二步操作无法进行,从而导致一些错误发生,所以引入了事务的使用,事务可以把许多步操作组合起来,要完成就一起完成,失败就都不会执行,从而保证了安全性,

事务的使用主要分为:开启事务、执行操作、提交事务。如果执行操作发生错误则跳过提交并回滚事务,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();

String SQL = "INSERT INTO Employees " +
"VALUES (106, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees " +
"VALUES (107, 22, 'Sita', 'Singh')";
stmt.executeUpdate(SQL);
// If there is no error.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback();
}

数据库连接池

数据库连接池就是一个实例,可以通过该实例得到数据库连接,该实例内部负责每一个数据库连接的分派和配置,数据库连接池把数据库连接的创建操作提取到了一”池子”中,以免每次需要数据库连接时都要去创建,它对数据库连接有了个统一的管理,如果程序需要仅仅需要从连接池中get即可.

durid

阿里旗下的durid提供了一个数据库连接池,用法如下:

  1. 导jar包

  2. 写配置文件”xxx.porperties”

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #连接设置
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/web
    username=root
    password=123456
    #<!-- 初始化连接 -->
    initialSize=10

    #最大连接数量
    maxActive=50

    #<!-- 最大空闲连接 -->
    maxIdle=20

    #<!-- 最小空闲连接 -->
    minIdle=5

    #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
    maxWait=60000
  3. 编写代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public void demo1() {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
    // 使用连接池:
    // 从属性文件中获取:
    Properties properties = new Properties();
    properties.load(new FileInputStream("day08_jdbc/src/druid.properties"));
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    // 获得连接:
    conn = dataSource.getConnection();// DruidPooledConnection
    // 编写SQL:
    String sql = "select * from account";
    // 预编译SQL:
    pstmt = conn.prepareStatement(sql);
    // 设置参数:
    // 执行SQL:
    rs = pstmt.executeQuery();
    while (rs.next()) {
    System.out.println(rs.getInt("id") + " " + rs.getString("name") + " " + rs.getDouble("money"));
    }
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    JDBCUtils.release(rs, pstmt, conn);
    }
    }

c3p0

另外一款数据库连接池,使用方便,以后项目中可以引入

c3p0的配置文件有要求,必须以 “c3p0-config.xml” 来命名,内部格式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/web?useSSL=false</property>
<property name="user">root</property>
<property name="password">123456</property>
</default-config>

<!-- 配置文件内部属性很多,这仅仅列举了一小部分,请前往官网看 -->
<!-- <named-config name="oracle">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web_test4</property>
<property name="user">root</property>
<property name="password">abc</property>
</named-config> -->
</c3p0-config>

可以进行默认设置,也可以进行命名设置.区别后面代码部分说.

并且该配置文件的位置必须在src目录中(遇到过放在外面的坑).

java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void demo1() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 获得连接:从连接池中获取:
// 创建连接池://创建连接池默认去类路径下查找c3p0-config.xml
DataSource dataSource = new ComboPooledDataSource();
//DataSource dataSource = new ComboPooledDataSource("name");
// 从连接池中获得连接:
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from account";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 执行SQL:
rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id") + " " + rs.getString("name") + " " + rs.getDouble("money"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, pstmt, conn);
}
}

上述代码中有:

1
2
DataSource dataSource = new ComboPooledDataSource();
//DataSource dataSource = new ComboPooledDataSource("name");

如果无参数,则使用配置文件中的default-config标签下的配置,如果有个String类型的参数,则使用配置文件中name属性为该string的named-config标签下的配置,

也就是说c3p0的配置文件可以同时配置多个数据库的连接信息,比Druid好用辣么一点点.

DBUtils

一个对数据库连接java代码简单封装的类库,适合轻量级的一些项目,可以被Hibernate或者MyBatis代替,这里只是简单的介绍下吧,不做深入讲解.

核心类就是个QueryRunner,用法如下:

1
2
3
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
//JDBCUtils.getDataSource()是自定义的一个类,用于获得连接池对象
//例如c3p0的DataSource dataSource = new ComboPooledDataSource();

接着通过QueryRunner对象就可对数据库为所欲为(成语接龙开始….)了.

增删改

1
2
3
4
5
6
7
//增
Object[] objs = {"ddd", 10000};
queryRunner.update("insert into account values (null,?,?)", objs);
//删
queryRunner.update("delete from account where id = ?", 3);
//改
queryRunner.update("update account set name=?,money=? where id =?", "eee", 20000, 4);

查询

查询复杂点,用到了query()方法,参数有2+个,第一个为sql语句,第二个为ResultSetHandler接口,c3p0给了它9个实现类,分别为:

  1. ArrayListHandler
  2. ArrayHandler
  3. BeanHandler
  4. BeanListHandler
  5. BeanMapHandler
  6. ColumnListHandler
  7. KeyedHandler
  8. MapListHandler
  9. ScalarHandler

包含List的命名都返回一个List对象,用于查询出多条数据,下面给点例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
@Test
/**
* ArrayHandler:将一条记录封装到一个Object数组中
*/
public void demo1() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Object[] objs = queryRunner.query("select * from account where id = ?", new ArrayHandler(), 1);
System.out.println(Arrays.toString(objs));
}

@Test
/**
* ArrayListHandler:将多条记录封装到一个装有Object数组的List集合中 *
* 一条记录封装到Objecct[]数组中,多条记录就是多个Object[],那么多个Object数组就将其装入List集合中即可。
*/
public void demo2() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Object[]> list = queryRunner.query("select * from account", new ArrayListHandler());
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
}

@Test
/**
* BeanHandler:将一条记录封装到一个JavaBean中
*/
public void demo3() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Account account = queryRunner.query("select * from account where id = ?",
new BeanHandler<Account>(Account.class), 2);
System.out.println(account);
}

@Test
/**
* BeanListHandler:将多条记录封装到一个装有JavaBean的List集合中。
* *一条记录就是一个Java的对象(JavaBean),如果多条记录(多个Java的对象),将多个Java对象装到一个List集合中。
*/
public void demo4() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Account> list = queryRunner.query("select * from account ", new BeanListHandler<Account>(Account.class));
for (Account account : list) {
System.out.println(account);
}
}

@Test
/**
* MapHandler:将一条记录封装到一个Map集合中,Map的key是列名,Map的value就是表中列的记录值。
*/
public void demo5() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Map<String, Object> map = queryRunner.query("select * from account where id = ?", new BeanMapHandler(), 4);
System.out.println(map);
}

@Test
/**
* MapListHandler:将多条记录封装到一个装有Map的List集合中。
*/
public void demo6() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Map<String, Object>> list = queryRunner.query("select * from account", new MapListHandler());
for (Map<String, Object> map : list) {
System.out.println(map);
}
}

@Test
/**
* ColumnListHandler:将某列的值封装到List集合中
*/
public void demo7() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
List<Object> list = queryRunner.query("select name,money from account", new ColumnListHandler("name"));
for (Object object : list) {
System.out.println(object);
}
}

@Test
/**
* ScalarHandler:单值封装
*/
public void demo8() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Object obj = queryRunner.query("select count(*) from account", new ScalarHandler());
System.out.println(obj);
}

@Test
/**
* KeyedHandler:将一条记录封装到一个Map集合中。将多条记录封装到一个装有Map集合的Map集合中。而且外面的Map的key是可以指定的。
*/
public void demo9() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
Map<Object, Map<String, Object>> map = queryRunner.query("select * from account", new KeyedHandler("id"));
for (Object key : map.keySet()) {
System.out.println(key + " " + map.get(key));
}
}