javaJDBC的一系列操作

####Mysql连接

1.步骤

  • 加载驱动数据库驱动,不需要自己实例化 由容器自动完成
  • 如 Class.forName(com.mysql.cj.jdbc.Driver);

2.连接数据库

这里创建了一个connect对象,可以查看API 使用connect 和DriverManager的方法

  • Connection connect = DriverManager.getConnection(
    DBURL,USER,PASSWORD);
    
  • 第一个属性是url 如: jdbc:mysql://localhost:3306/myfirstdb
  • 3306端口是mysql默认绑定的端口号 myfirstdb是你创建的数据库名称
  • USER 账户名 如:root
  • PASSWORD 密码

4.数据库关闭
connect.close();

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.diedline.mysql;

import java.sql.Connection;
import java.sql.DriverManager;

public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "mypassword";
public static void main(String[] args) throws Exception {
//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//4.关闭数据库
connect.close();
}
}

####常见错误

#####1.监听服务出现错误

监听的主机名称不是本机的计算机名称,也不要使用ip地址。

#####2.UID错误,即你要连接的数据库的名字错误。

在命令行或者其他数据库管理工具可以查看数据库和创建数据库。

在JDBC操作中,在驱动数据库连接对象时采用的是工厂设计模式,而DriverManager就是一个工厂类

客户端调用的时候会完全隐藏具体的实现子类

####数据库的更新和查询操作

当你取得connection对象时就可以使用其中的方法createStatement 取得接口对象

Statement createStatement() throws SQLException

  • 数据更新操作 返回的int值是返回更新行数
    • int executeUpdate(String sql)
      throws SQLException
      
  • 执行给定的SQL语句,这可能是INSERT , UPDATE ,或DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。

  • 数据查询操作

  • ResultSet executeQuery(String sql)
    throws SQLException执行给定的SQL语句,返回单个ResultSet对象。
    
  • 返回的ResultSet跟set没有任何关系

范例

增加删更新都是直接写sql语句就行替换下例中的String sql就行。

添加一条数据到数据

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

package com.diedline.mysql;

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

public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxx";
public static void main(String[] args) throws Exception {
//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//3.进行数据库的数据操作
Statement statement = connect.createStatement();
//在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
String sql = "insert into student ( name ,register_date) " +
" value(\"张三\",\"2018-12-13\");";
int len = statement.executeUpdate(sql); //执行sql返回更新的数据行数
System.out.println("受影响的数据行:"+len);
//4.关闭数据库
connect.close();
}
}

####数据查询

使用 SELECT进行查询的时候实际上会将所有的查询结果返回给用户显示,而显示的基本形式就是表的形式,可是如果要进行我们的查询,这些查询的结果应该返回给程序,由用户来进行处理,那么就必须有一种类型可以接收所有的返回结果,在数据库中虽然可能有几百张数据表,但是整个数据表的组成类型都是固定的,所以在ResultSet设计的过程之中是按照数据类型

在ResultSet接口里面定义了如下的方法 查看ResultSet接口其中的方法就能实现查询

  • 向下移动指针并判断是否有数据行Reult.next
    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

    package com.diedline.mysql;

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

    public class Test {
    private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
    "useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
    "&useLegacyDatetimeCode=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "xxxxx";
    public static void main(String[] args) throws Exception {
    //1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
    Class.forName(DBDRIVER);
    //2.连接数据库
    Connection connect = DriverManager.getConnection(
    DBURL,USER,PASSWORD);
    System.out.println(connect);
    //3.进行数据库的数据操作
    Statement statement = connect.createStatement();
    //在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
    String sql = "SELECT name FROM student;";
    ResultSet result = statement.executeQuery(sql);
    while (result.next()){ //循环
    String name = result.getString("name");
    System.out.println("姓名:" + name);
    }
    //4.关闭数据库
    connect.close();
    }
    }

既然已经可以执行查询了,那么就可以继续添加实现各种复杂查询,例如限定查询。分组统计查询。子查询。

注意:

1.使用 getxxx()取出列数据的时候,强烈建议按照给定的数据取

2.每一个列数数据只能按照顺序取一次

以上的代码在取列内容的时候重复编写了列名称,这一点实际上可以忽略,因为在写sql语句的时候就已经明确给出了列名称

####总结

Statement接口的执行步骤几乎都是固定的,并且最方便的是可以直接执行sql的字符串操作,但是任何的开发都不可能去使用Statement。以后都要去使用PreparedStatement接口。

####Statement接口问题
虽然jdbc中提供了Statement接口,但是从实际来讲,Statement接口中存在有严重的操作缺陷,是不可能在实际的工作中使用的,

如果出现SQLSyntax错误就去查找你的Sql语句是否出错

StateMent如果想要变成灵活的应用,那么必须采用拼凑字符串的形式完成如果输入的内容存在有“’”,那么整个sql就会出错,也就是说StateMent的执行模式不适合一些敏感字符。

####PreparedStatment操作

Statment的问题在于它需要一个完整的字符串来定义需要使用的SQL语句,所有导致在使用中需要进行大量的SQL拼凑PreparedStatment操作和Statment不同的地方在于,它执行的是一个完整的具备特殊占位标记的SQL语句,并且可以动态的设置所需要的数据。

PreparedStatment属于Statment的子接口,但是如果想要取得这个子接口的实例对象Connection接口所提供的方法PreparedStatement prepareStatement(String sql)
throws SQLException

注意这个方法是prepare 不是prepared ,里面在执行的时候需要传入sql语句,这个sql是具备特殊标记的完整sql,但是此时没有内容,当取得PreparedStatement接口对象时需要使用一系列的setXXX()方法用于为所使用的标记设置具体内容,而后对于执行操作,有两个方法支持

  • 更新操作 executeUpdate() 不接收sql语句
  • 查询操作 executeQuery() 同不接收
  • 返回值都是ResultSet

注意当使用了PreparedStatement接口操作时,最需要注意的是里面的setDate方法,因为此方法使用的是java.sql.Date

在java.util.Date类下有三个子类都是在java.sql包中的:

  • java.sql.Date: 描述的是日期
  • java.sql.Time:描述的是时间
  • java.sql.TimeStamp: 描述的是时间戳(日期和时间)

如果要将java.util.Date变成java.sql.Date(Time TimeStamp) 只能依靠long 完成

  • java.util.Date: public long getTime() 可以将Date变为long

范例:

改进数据增加

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxxx";
public static void main(String[] args) throws Exception {
String name1 = "隔壁老王";
Date date = new Date();

//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
String sql = "insert into student ( name ,register_date) " +
" values(?,?);";
//3.进行数据库的数据操作,执行了完整的sql语句
PreparedStatement preparedStatement = connect.prepareStatement(sql);
//下面是按照?对应的顺序写sql语句 默认是从1开始的
preparedStatement.setString(1,name1);
//使用sql.date中的构造传入util.date返回的long值
preparedStatement.setDate(2,new java.sql.Date(date.getTime()));
int len = preparedStatement.executeUpdate(); //执行sql返回更新的数据行数
System.out.println("受影响的数据行:"+len);
//4.关闭数据库
connect.close();
}
}

更新删除操作和增加操作的区别不大

整个数据库操作里面更新操作几乎都是固定的模式,但是查询操作是最复杂的。

范例:

1.查询所有数据

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.*;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxx";
public static void main(String[] args) throws Exception {
String name1 = "隔壁老王";
Date date = new Date();

//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
String sql = "SELECT id,name,register_date FROM student ORDER BY id;";
//3.进行数据库的数据操作,执行了完整的sql语句
PreparedStatement preparedStatement = connect.prepareStatement(sql);
//下面是按照?对应的顺序写sql语句 默认是从1开始的
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int nid = resultSet.getInt(1) ;
String name = resultSet.getString(2);
Date date1 = resultSet.getDate(3);
System.out.println(nid+","+name+","+date1);
}

//4.关闭数据库
connect.close();
}
}

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.*;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxxx";
public static void main(String[] args) throws Exception {
String name1 = "隔壁老王";
Date date = new Date();
String keyWord = "wch";

//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
String sql = "SELECT id,name,register_date FROM student WHERE name LIKE ?;";
//3.进行数据库的数据操作,执行了完整的sql语句
PreparedStatement preparedStatement = connect.prepareStatement(sql);
//下面是按照?对应的顺序写sql语句 默认是从1开始的
preparedStatement.setString(1,"%"+keyWord+"%");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int nid = resultSet.getInt(1) ;
String name = resultSet.getString(2);
Date date1 = resultSet.getDate(3);
System.out.println(nid+","+name+","+date1);
}

//4.关闭数据库
connect.close();
}
}

3.统计模糊查询的数据量使用COUNT()函数

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.*;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxxx";
public static void main(String[] args) throws Exception {
int currentPage = 1;
int lineSize = 3;
String name1 = "隔壁老王";
Date date = new Date();
String keyWord = "wch";

//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
System.out.println(connect);
//在编写sql语句时,如果太长需要换行,那么请一定要前后加上空格
String sql = "SELECT COUNT(id) FROM student where name LIKE ?";
//3.进行数据库的数据操作,执行了完整的sql语句
PreparedStatement preparedStatement = connect.prepareStatement(sql);
//下面是按照?对应的顺序写sql语句 默认是从1开始的
preparedStatement.setString(1,"%"+keyWord+"%");
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()){ //因为只返回一行数据
int count = resultSet.getInt(1);
System.out.println(count);
}

//4.关闭数据库
connect.close();
}
}

总结:

在以后任何的开发都是使用的是PreparedStatement接口

####批处理

批处理:一次性向数据库发出多条操作命令,一起执行。

Statement 中批处理的方法

添加批处理命令

void addBatch()
throws SQLException

执行批处理命令

int[] executeBatch()
throws SQLException

返回的数组是包含了所有批处理语句的执行结果,返回的是每条语句影响的行数;

执行批处理

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.*;
import java.util.Arrays;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxx";
public static void main(String[] args) throws Exception {
int currentPage = 1;
int lineSize = 3;
String name1 = "隔壁老王";
Date date = new Date();
String date1 = date.toString();
String keyWord = "wch";
//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
Statement statement = connect.createStatement();
statement.addBatch("INSERT INTO student(id,name,register_date) values (7,'测试a','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (8,'测试b','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (9,'测试c','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (10,'测试d','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (11,'测试e','2018-12-15')");

int[] result = statement.executeBatch(); //执行批处理
System.out.println(Arrays.toString(result));
//4.关闭数据库
connect.close();
}
}

如果假设以上的五条批处理属于一组关联的操作,如果中间有一条语句执行失败,其他的不应该成功。
在批处理操作过程中,由于jdbc具有自动的事务提交,所以一旦中间的语句出现问题,那么结果就是错误前的语句正常执行,错误后的语句不执行。

所以可以使用jdbc的提供的事务操作来进行手工的事务控制,所有的操作方法都在Connection接口中定义

  • 事务提交 void commit()
    throws SQLException
  • 事务回滚 void rollback()
    throws SQLException
    
  • 设置是否为自动提交void setAutoCommit(boolean autoCommit)
    throws SQLException
    

例子:

利用事务处理出现异常进行回滚

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
package com.diedline.mysql;

import javax.xml.crypto.Data;
import java.sql.*;
import java.util.Arrays;
import java.util.Date;


public class Test {
private static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
private static final String DBURL = "jdbc:mysql://localhost:3306/myfirstdb?" +
"useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +
"&useLegacyDatetimeCode=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "xxxx";
public static void main(String[] args) throws Exception {
int currentPage = 1;
int lineSize = 3;
String name1 = "隔壁老王";
Date date = new Date();
String date1 = date.toString();
String keyWord = "wch";
//1.加载驱动数据库驱动,不需要自己实例化 由容器自动完成
Class.forName(DBDRIVER);
//2.连接数据库
Connection connect = DriverManager.getConnection(
DBURL,USER,PASSWORD);
Statement statement = connect.createStatement();
connect.setAutoCommit(false); //取消自动提交
try {
statement.addBatch("INSERT INTO student(id,name,register_date) values (7,'测试a','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (8,'测试b','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (9,'测试c','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (10,'测试d','2018-12-15')");
statement.addBatch("INSERT INTO student(id,name,register_date) values (11,'测试e','2018-12-15')");

int[] result = statement.executeBatch(); //执行批处理
System.out.println(Arrays.toString(result));
connect.commit(); //如果没有错误进行提交
} catch (SQLException e) {
e.printStackTrace();
connect.rollback(); //如果出现异常,进行回滚
}
//4.关闭数据库
connect.close();
}
}

以上只是演示下如何手工处理事务,而在实际事务中这些操作意义不大。意义不大指的是日后的容器会帮我们自动处理。