####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 { Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); connect.close(); } }
|
####常见错误
#####1.监听服务出现错误
监听的主机名称不是本机的计算机名称,也不要使用ip地址。
#####2.UID错误,即你要连接的数据库的名字错误。
在命令行或者其他数据库管理工具可以查看数据库和创建数据库。
在JDBC操作中,在驱动数据库连接对象时采用的是工厂设计模式,而DriverManager就是一个工厂类
客户端调用的时候会完全隐藏具体的实现子类
####数据库的更新和查询操作
当你取得connection对象时就可以使用其中的方法createStatement 取得接口对象
Statement createStatement() throws SQLException
范例
增加删更新都是直接写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 { Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); Statement statement = connect.createStatement(); String sql = "insert into student ( name ,register_date) " + " value(\"张三\",\"2018-12-13\");"; int len = statement.executeUpdate(sql); System.out.println("受影响的数据行:"+len); 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 { Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); Statement statement = connect.createStatement(); String sql = "SELECT name FROM student;"; ResultSet result = statement.executeQuery(sql); while (result.next()){ String name = result.getString("name"); System.out.println("姓名:" + name); } 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();
Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); String sql = "insert into student ( name ,register_date) " + " values(?,?);"; PreparedStatement preparedStatement = connect.prepareStatement(sql); preparedStatement.setString(1,name1); preparedStatement.setDate(2,new java.sql.Date(date.getTime())); int len = preparedStatement.executeUpdate(); System.out.println("受影响的数据行:"+len); 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();
Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); String sql = "SELECT id,name,register_date FROM student ORDER BY id;"; PreparedStatement preparedStatement = connect.prepareStatement(sql); 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); }
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";
Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); String sql = "SELECT id,name,register_date FROM student WHERE name LIKE ?;"; PreparedStatement preparedStatement = connect.prepareStatement(sql); 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); }
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";
Class.forName(DBDRIVER); Connection connect = DriverManager.getConnection( DBURL,USER,PASSWORD); System.out.println(connect); String sql = "SELECT COUNT(id) FROM student where name LIKE ?"; PreparedStatement preparedStatement = connect.prepareStatement(sql); preparedStatement.setString(1,"%"+keyWord+"%"); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()){ int count = resultSet.getInt(1); System.out.println(count); }
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"; Class.forName(DBDRIVER); 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)); 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"; Class.forName(DBDRIVER); 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(); } connect.close(); } }
|
以上只是演示下如何手工处理事务,而在实际事务中这些操作意义不大。意义不大指的是日后的容器会帮我们自动处理。