JDBC基础语法
简介
- 什么是JDBC
- 是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法,我们通常说的JDBC是面向关系型数据库的
- 通俗的说就是java公司编写的一套规范,和Java连接的数据库,都要遵守这个规范来编写驱动程序。
使用步骤
-
以mySQL为例,展示数据库与ieda的连接
-
由于Java只是给出了规范没有具体的连接数据的类,所以我们需要导入第三方编写好的类来连接
- 在官网上下载jar包,将包导入到程序中,通常在程序中创建lib文件夹,导入后一定要依赖一下
-
和数据库的连接步骤
-
通过反射加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
-
获取连接对象
String url="jdbc:mysql://127.0.0.1:3306/shoping?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8"; String username="root"; String password="13892035"; DriverManager.getConnection(url,username,password);
要注意由于数据库的版本不相同,在定义url上也有区别,数据库8.0是上述表示定义的。5.7的url是这样定义的:String url=“jdbc:mysql://localhost:3306/mydb”;
-
获取操作对象
Connection connection = DriverManager.getConnection(url, username, password); PreparedStatement preparedStatement = connection.prepareStatement("select *from users");
-
发送sql语句
ResultSet resultSet = preparedStatement.executeQuery();
-
释放资源
connection.close(); preparedStatement.close(); resultSet.close();
以上就是Java连接数据库的基本操作步骤
-
获取操作对象
-
获取操作对象的两种方式
-
Statement statement = connection.createStatement();
statement.executeQuery(“select *from users”);这种方式获取操作对象,在发送sql语句时,可能有sql注入发生,这样就会产生非法获取数据,因此这种方式获取操作对象我们一般是不用的
-
PreparedStatement preparedStatement = connection.prepareStatement(“select *from users”);
表示预编译的 SQL 语句的对象。SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。使用如下
Connection connection2 = JDBCUtils.getConnection(); //获取预编译sql语句对象 PreparedStatement preparedStatement1 = connection2.prepareStatement("select users.id,users.username,orders.oid,miditem.ppid,products.*from users join orders on users.id=orders.uid and users.username=? join miditem on orders.oid=miditem.ooid join products on miditem.ppid=products.pid "); //设置?的参数值 preparedStatement1.setString(1, name); ResultSet resultSet3 = preparedStatement1.executeQuery();
-
发送sql语句
-
预编译对象发送sql语句
返回值 方法 描述 boolean execute() 发送SQL语句,这个语句可以是各种类型的,一些预处理过的语句返回多个结果,execute 方法处理这些复杂的语句 void addBatch() 将一组参数添加到此 PreparedStatement 对象的批处理命令中。 int[] executeBatch() 发送批处理操作 ResultSet executeQuery() 执行sql查询,并返回查询的结果集 int executeUpdate() 该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERT、UPDATE 或 DELETE 语句; -
批处理,先将要发送的数据添加到批处理,先存在缓存中,这样比一条条发送数据效率要高,
Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement("insert into demo(username,upassword) values(?,?)"); preparedStatement.setString(1,"liuhao"); preparedStatement.setString(2,"1234556"); //添加到批处理中 preparedStatement.addBatch(); preparedStatement.setString(1,"lihui"); preparedStatement.setString(2,"1234556"); preparedStatement.addBatch(); preparedStatement.setString(1,"zhaowei"); preparedStatement.setString(2,"1234556"); preparedStatement.addBatch(); //发送批处理操作 long[] longs = preparedStatement.executeBatch();
-
-
获取自增键
有时候我们在添加数据的时候,需要获取自增长的键值,这样我们就要在获取操作对象时,就要添加一个参数:Statement.RETURN_GENERATED_KEYS
//获取自增长键值 PreparedStatement preparedStatement = connection2.prepareStatement("insert into orders(uid) values (?)", Statement.RETURN_GENERATED_KEYS); preparedStatement.setInt(1, userId); int i = preparedStatement.executeUpdate(); if (i == 1) { ResultSet oid = preparedStatement.getGeneratedKeys(); while (oid.next()){ ooid = oid.getInt(1); }
事务
-
概念:数据库中的一个操作,这个操作肯能有很多步骤,但是要将这些步骤看成一个整体操作,要么同时成功,或者同时失败,而不能以部分成功,一部分失败。提交失败就回滚到原来的状态
- 例如,在银行取钱过程这就是一个事务,账户余额查询,减少,出钱,这几个步骤就要同时成功,或者同时失败。
-
在现在的数据库中,默认自动开启事务
-
事务的四大特性:
原子性:事务的操作不可分割,要么同时成功,要么同时失败
一致性:事务必须让数据库从一个一致性状态切换到另一个一致性状态
隔离性:数据库被多个用户并发访问时,数据库为每个客户开启的事务不能被其他事务的数据访问。
持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
-
事务的创建
//示例1 //订单在创建一半时,如果出现异常就要回滚到原来的状态 connection2.setAutoCommit(false);// 设置事务 // Savepoint savepoint = connection2.setSavepoint(); 如果想要回到指定的点,那就要设置事务的回滚点 ResultSet resultSet1 = null; int ooid = 0; try { PreparedStatement statement1 = connection2.prepareStatement("select id from users where username=?"); statement1.setString(1, name); resultSet1 = statement1.executeQuery(); ooid = -1; if (resultSet1.next()) { int userId = resultSet1.getInt(1); PreparedStatement preparedStatement = connection2.prepareStatement("insert into orders(uid) values (?)", Statement.RETURN_GENERATED_KEYS); preparedStatement.setInt(1, userId); int i = preparedStatement.executeUpdate(); if (i == 1) { ResultSet oid = preparedStatement.getGeneratedKeys(); while (oid.next()) { ooid = oid.getInt(1); } // System.out.println(oid); System.out.println("请输入商品编号 0:退出并提交"); Scanner sc2 = new Scanner(System.in); boolean flag = true; while (flag) { int produnctNum = sc2.nextInt(); if (produnctNum != 0) { PreparedStatement preparedStatement1 = connection2.prepareStatement("insert into miditem(ooid,ppid) values (?,?)"); preparedStatement1.setInt(1, ooid); preparedStatement1.setInt(2, produnctNum); int i1 = preparedStatement1.executeUpdate(); if (i1 == 1) { System.out.println("提交成功"); } else { System.out.println("订单提交失败"); } } else { flag = false; } } } } } catch (Exception throwables) { // 如果出错就回滚到原来的状态 connection2.rollback(); } finally { // 完成就提交事务 connection2.commit(); } //示例2 try { conn = JDBCUtils.getConnection(); conn.setAutoCommit(false); //把事务设置为手动提交。 String sql1 = "UPDATE bank SET money=money-1000 WHERE NAME='zhangsan'"; PreparedStatement preparedStatement = conn.prepareStatement(sql1); int i = preparedStatement.executeUpdate(); //模拟异常 //System.out.println(1/0); //加钱 String sql2 = "UPDATE bank SET money=money+1000 WHERE NAME='lisi'"; PreparedStatement preparedStatement2 = conn.prepareStatement(sql2); int i2 = preparedStatement2.executeUpdate(); System.out.println("===================================="); //设置回滚点 //hehe = conn.setSavepoint(); //第二次转账 String sql3 = "UPDATE bank SET money=money-500 WHERE NAME='zhangsan'"; PreparedStatement preparedStatement3 = conn.prepareStatement(sql3); preparedStatement3.executeUpdate(); //模拟异常 System.out.println(1 / 0); //加钱 String sql4 = "UPDATE bank SET money=money+500 WHERE NAME='lisi'"; PreparedStatement preparedStatement4 = conn.prepareStatement(sql4); preparedStatement4.executeUpdate(); } catch (Exception e) { e.printStackTrace(); //一旦遇到异常,就回滚事务 conn.rollback(); //回滚到回滚点的地方 // conn.rollback(hehe); }finally { //手动提交事务 conn.commit(); }
-
事务的隔离
- 事务在不同的隔离等级下有不同的数据访问状态
- read uncommitted 读未提交 上面的三个问题都会出现 出现数据脏读
- read committed 读已提交 可以避免脏读的发生 Oracle 默认级别
- epeatable read 可重复读 可以避免脏读和不可重复读的发生 MySQL 默认级别
- serializable 串行化 可以避免所有的问题
-
不隔离产生的问题
脏读:在一个事务中读取到另一个事务没有提交的数据
不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作) 不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作) 无法演示出来,MySQL已经默认避免了
和不可重复读的发生 MySQL 默认级别
- serializable 串行化 可以避免所有的问题
-
不隔离产生的问题
脏读:在一个事务中读取到另一个事务没有提交的数据
不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作) 不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作) 无法演示出来,MySQL已经默认避免了
-
数据库默认的就是epeatable read 的数据访问状态,一般情况下我们不会去修改这个状态。