一,简介

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序

二,编写JDBC程序

首先在mysql中创建一个库,并创建user表和插入表的数据,SQL脚本如下:

CREATE DATABASE jdbcLibrary CHARACTER SET utf8 COLLATE utf8_general_ci;
 
USE jdbcLibrary;
 
CREATE TABLE users(
id INT PRIMARY KEY,
uname VARCHAR(40),
upwd VARCHAR(40)
);
INSERT INTO users(id,uname,upwd) VALUES(1,'Zender','');
INSERT INTO users(id,uname,upwd) VALUES(2,'张三','');
INSERT INTO users(id,uname,upwd) VALUES(3,'李四','');

项目中导入驱动:

JDBCDemo代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
 
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//要连接的数据库URL
String url = "jdbc:mysql://localhost:3306/jdbcLibrary";
//用户名
String username = "root";
//密码
String password = "123456"; //1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取与数据库的链接
Connection conn = DriverManager.getConnection(url, username, password); //3.获取用于向数据库发送sql语句的statement
Statement st = conn.createStatement(); String sql = "select id,uname,upwd from users";
//4.向数据库发sql,并获取代表结果集的resultset
ResultSet rs = st.executeQuery(sql); //5.取出结果集的数据
while(rs.next()){
System.out.println("id=" + rs.getObject("id"));
System.out.println("uname=" + rs.getObject("uname"));
System.out.println("upwd=" + rs.getObject("upwd"));
} //6.关闭链接,释放资源
rs.close();
st.close();
conn.close();
}
}

运行结果:

1,DriverManager类

DriverManager用于加载驱动,并创建与数据库的链接。

API的常用方法:

DriverManager.registerDriver(new Driver())

DriverManager.getConnection(url, user, password)

注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:

1、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。

2、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。

推荐方式:Class.forName("com.mysql.jdbc.Driver")

采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。

2,Connection类

用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的。

常用方法:

createStatement()

创建向数据库发送sql的statement对象。

prepareStatement(sql)

创建向数据库发送预编译sql的PrepareSatement对象。

prepareCall(sql)

创建执行存储过程的callableStatement对象。

setAutoCommit(boolean autoCommit)

设置事务是否自动提交。

commit()

在链接上提交事务。

rollback()

在此链接上回滚事务。

3,Statement类

用于向数据库发送SQL语句

常用方法:

executeQuery(String sql)

用于向数据发送查询语句。

executeUpdate(String sql)

用于向数据库发送insert、update或delete语句

execute(String sql)

用于向数据库发送任意sql语句

addBatch(String sql)

把多条sql语句放到一个批处理中。

executeBatch()

向数据库发送一批sql语句执行。

4,ResultSet类

该类代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。

常用方法:

获取任意类型的数据:

    getObject(int index)

    getObject(string columnName)

获取指定类型的数据:

    getString(int index)

    getString(String columnName)

next()

移动到下一行

Previous()

移动到前一行

absolute(int row)

移动到指定行

beforeFirst()

移动resultSet的最前面。

afterLast()

移动到resultSet的最后面。

二,数据库的CRUD

创建一个db.properties文件用于存放MySQL数据库的连接信息,代码如下所示:

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/jdbcLibrary

username=root

password=123456

编写一个JdbcUtils工具类,用于连接数据库,获取数据库连接和释放数据库连接,代码如下:

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
 
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null; static{
try{
//读取db.properties文件中的数据库连接信息
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in); //获取数据库连接驱动
driver = prop.getProperty("driver");
//获取数据库连接URL地址
url = prop.getProperty("url");
//获取数据库连接用户名
username = prop.getProperty("username");
//获取数据库连接密码
password = prop.getProperty("password"); //加载数据库驱动
Class.forName(driver); }catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
} /**
*
* @方法名: getConnection
* @描述: 获取数据库连接对象
* @return
* @throws SQLException
* @创建人 Zender
*/
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, username,password);
} /**
*
* @方法名: release
* @描述: 释放资源
* @param conn
* @param st
* @param rs
* @创建人 Zender
*/
public static void release(Connection conn,Statement st,ResultSet rs){
try{
if(rs!=null){
rs.close();
rs = null;
}
if(st!=null){
st.close();
st = null;
}
if(conn!=null){
conn.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
}

JDBCDemo代码如下:

package com.zender;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
 
import org.junit.Test;
 
import com.zender.util.JdbcUtils;
 
public class JDBCDemo { private Connection conn = null;
private PreparedStatement st = null;
private ResultSet rs = null; @Test
public void insertUser(){
try{
//获取一个数据库连接
conn = JdbcUtils.getConnection();
//构建执行的SQL,SQL中的参数使用?作为占位符
String sql = "INSERT INTO users(id,uname,upwd) VALUES(?,?,?);"; //获取prepareStatement对象
st = conn.prepareStatement(sql);
st.setInt(1, 6);
st.setString(2, "Zender");
st.setString(3, "123456");
//执行插入操作,executeUpdate方法返回成功的条数
int num = st.executeUpdate();
if(num>0){
System.out.println("插入成功!!");
} }catch (Exception e) {
e.printStackTrace();
}finally{
//SQL执行完成之后释放相关资源
JdbcUtils.release(conn, st, rs);
}
} @Test
public void deleteUser(){
try{
conn = JdbcUtils.getConnection();
String sql = "delete from users where id=4";
st = conn.prepareStatement(sql);
int num = st.executeUpdate();
if(num>0){
System.out.println("删除成功!!");
}
}catch (Exception e) {
e.printStackTrace(); }finally{
JdbcUtils.release(conn, st, rs);
}
} @Test
public void deleteUpdate(){
try{
conn = JdbcUtils.getConnection();
String sql = "update users set uname='修改的Name', upwd='123' where id=1";
st = conn.prepareStatement(sql);
int num = st.executeUpdate();
if(num>0){
System.out.println("更新成功!!");
}
}catch (Exception e) {
e.printStackTrace(); }finally{
JdbcUtils.release(conn, st, rs);
}
} @Test
public void findUser(){
try{
conn = JdbcUtils.getConnection();
String sql = "select * from users where id=3";
st = conn.prepareStatement(sql);
rs = st.executeQuery();
if(rs.next()){
System.out.println(rs.getString("id"));
System.out.println(rs.getString("uname"));
System.out.println(rs.getString("upwd"));
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}

这里使用了PreperedStatement,该类是Statement的子类,PreperedStatement可以避免SQL注入的问题,并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换。

三,事务

事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

例如:模拟银行转账,User1向User2转账

数据库中创建名字为account的table:

JDBCDemo代码如下:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
 
import org.junit.Test;
 
import com.zender.util.JdbcUtils;
 
public class JDBCDemo { private Connection conn = null;
private PreparedStatement st = null;
private ResultSet rs = null; @Test
public void TransactionDemo(){
try{
//获取一个数据库连接
conn = JdbcUtils.getConnection();
//通知数据库开启事务
conn.setAutoCommit(false);
//构建执行的SQL
String sql = "update account set money=money-100 where id=1";
//获取prepareStatement对象
st = conn.prepareStatement(sql);
//执行修改操作
st.executeUpdate();
sql = "update account set money=money+100 where id=2";
st = conn.prepareStatement(sql);
st.executeUpdate();
//提交事务
conn.commit();
}catch (Exception e) {
//出现异常回滚事务
e.printStackTrace();
}finally{
//释放资源
JdbcUtils.release(conn, st, rs);
}
}
}

运行以上代码,数据库数据如下:

现在修改JDBCDemo代码,让代码在执行中途出错,导致有一部分SQL执行失败后,让数据库自动回滚事务,代码如下:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
 
import org.junit.Test;
 
import com.zender.util.JdbcUtils;
 
public class JDBCDemo { private Connection conn = null;
private PreparedStatement st = null;
private ResultSet rs = null; @Test
public void TransactionDemo(){
try{
//获取一个数据库连接
conn = JdbcUtils.getConnection();
//通知数据库开启事务
conn.setAutoCommit(false);
//构建执行的SQL
String sql = "update account set money=money-100 where id=1";
//获取prepareStatement对象
st = conn.prepareStatement(sql);
//执行修改操作
st.executeUpdate();
//出错代码
int x = 1/0;
sql = "update account set money=money+100 where id=2";
st = conn.prepareStatement(sql);
st.executeUpdate();
//提交事务
conn.commit();
}catch (Exception e) {
//出现异常回滚事务
e.printStackTrace();
}finally{
//释放资源
JdbcUtils.release(conn, st, rs);
}
}
}

运行以上代码,控制台报错:

数据库数据如下:

四,事务的四大特性

原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。比如在同一个事务中的SQL语句,要么全部执行成功,要么全部执行失败。

一致性(Consistency)

事务必须使数据库从一个一致性状态变换到另外一个一致性状态。以转账为例子,user1向user2转账,假设转账之前这两个用户的钱加起来总共是200,那么user1向user2转账之后,不管这两个账户怎么转,user1用户的钱和user2用户的钱加起来的总额还是200,这个就是事务的一致性。

隔离性(Isolation)

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

事务的四大特性中最麻烦的是隔离性,下面重点介绍一下事务的隔离级别

五、事务的隔离级别

作用:

在多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。

不考事务的虑隔离性,可能出现以下问题:

1,脏读

脏读指一个事务读取了另外一个事务未提交的数据。

例如:

假设user1向user2转帐100元,对应sql语句如下所示:

    SQL1:update account set money=money+100 where name='user2'

    SQL2:update account set money=money-100 where name='user1'

 当SQL1执行完,SQL2还没执行(user1未提交时),如果此时user2查询自己的帐户,就会发现自己多了100元钱。如果user1等user2走后再回滚,user2回来再次查询时候就会少100元。 

2,不可重复读

不可重复读指在一个事务内读取表中的某一行数据,多次读取结果不同。

例如:

1,首先银行查询用户user1的余额,第一次查询结果为100元。

2,user1来到银行查询自己余额,查询的余额为100元,然后user1向账户中存入了500元并提交。

3,银行接着又进行了一次查询,此时A帐户为600元了。银行两次查询不一致,可能就会很困惑,不知道哪次查询是准的。

3,虚读(幻读)

虚读(幻读)是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

例如:

user1去银行存款500元(事务没有提交),这时候银行做总存款统计,所有用户存款为1000元,然后user1这个时候提交事务,这时银行再统计发现帐户钱多了500元,造成虚读。可能就会很困惑,不知道哪次查询是准的。

Java Web学习总结(11)JDBC的更多相关文章

  1. [原创]java WEB学习笔记11:HttpServlet(HttpServletRequest HttpServletRsponse) 以及关于 Servlet 小结

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  2. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

  3. Java Web 学习路线

    实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...

  4. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  5. [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  6. Java Web 学习笔记 1

    Java Web 学习笔记 1 一.Web开发基础 1-1 Java Web 应用开发概述 1.1.1 C/S C/S(Client/Server)服务器通常采用高性能的PC机或工作站,并采用大型数据 ...

  7. Java Web学习笔记之---EL和JSTL

    Java Web学习笔记之---EL和JSTL (一)EL (1)EL作用 Expression  Language(表达式语言),目的是代替JSP页面中复杂的代码 (2)EL表达式 ${变量名} ( ...

  8. JAVA Web学习笔记

    JAVA Web学习笔记 1.JSP (java服务器页面) 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . JSP全名为Java Server Pages,中文名叫java服务器 ...

  9. Java Web学习系列——Maven Web项目中集成使用Spring

    参考Java Web学习系列——创建基于Maven的Web项目一文,创建一个名为LockMIS的Maven Web项目. 添加依赖Jar包 推荐在http://mvnrepository.com/.h ...

  10. Java web 学习之旅

    java web学习之旅 来公司十天了,感觉已经慢慢地融入了这个环境中,几个学长人都很好,都是在他们帮助下,我才能比较顺利的开始了学习java web的旅途. 来这里学习的第一个阶段是做一个简单的用户 ...

随机推荐

  1. php面试专题---14、Linux基础考点

    php面试专题---14.Linux基础考点 一.总结 一句话总结: php考linux其实也考不了很难 1.系统定时任务? crontab命令和 at命令 crontab命令 crontab -e ...

  2. WebGIS常用代码集锦

    一.普通代码 1.坐标转换 ol.proj.transform(coordinate, source, destination) ol.proj.transform(coordinate, 'EPSG ...

  3. Bing Advanced Search Tricks You Should Know

    Bing is one of the world's most popular search engines that has gained many fans with its ease of us ...

  4. inline-block的间隙问题 box-orient属性 line-clamp属性 margin问题

    只要设了 display:inline-block 将元素变成行级块元素的时候,会自带空隙,即使你设了 margin 和 padding 依然没有效果! 解决办法:只要在父元素上加上font-size ...

  5. fread fwrite文本模式读写回车换行符 自动转换问题

    fread  会把\r\n(0d0a)替换为\nfwrite 会把\n替换为\r\n(0d0a),\r\n会变成\r\r\n(0d0d0a) 今天在写一个日志类,用于打印服务程序的信息. 我将每一个日 ...

  6. Flask-SQLALchemy动态的filter_by和filter

    1.filter_by filter_by用于查询简单的列名,不支持比较运算符. filters = {'name': 'fengyao', 'age': 26} User.query.filter_ ...

  7. 本站CSS代码

    body { /*字体样式*/ font-family: "youyuan",幼圆,"MicrosoftJhengHei",华文细黑,STHeiti,MingL ...

  8. Java Web项目启动执行顺序

    一. 1.启动一个WEB项目,WEB容器会先去读取它的配置文件web.xml,读取<context-param>和<listener>两个节点. 2.接着,容器创建一个Serv ...

  9. jmeter对响应数据做断言

    单独校验某个接口中的某个字段时,断言就相当于检查点 添加http请求,输入路径url

  10. IDF-CTF-牛刀小试 writeup

    题目链接:http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=16 被改错的密码 从前有一个熊孩子入侵了一个网站的数据库, ...