Java Web学习总结(11)JDBC
一,简介
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的更多相关文章
- [原创]java WEB学习笔记11:HttpServlet(HttpServletRequest HttpServletRsponse) 以及关于 Servlet 小结
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问
本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...
- Java Web 学习路线
实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...
- [原创]java WEB学习笔记95:Hibernate 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java Web 学习笔记 1
Java Web 学习笔记 1 一.Web开发基础 1-1 Java Web 应用开发概述 1.1.1 C/S C/S(Client/Server)服务器通常采用高性能的PC机或工作站,并采用大型数据 ...
- Java Web学习笔记之---EL和JSTL
Java Web学习笔记之---EL和JSTL (一)EL (1)EL作用 Expression Language(表达式语言),目的是代替JSP页面中复杂的代码 (2)EL表达式 ${变量名} ( ...
- JAVA Web学习笔记
JAVA Web学习笔记 1.JSP (java服务器页面) 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . JSP全名为Java Server Pages,中文名叫java服务器 ...
- Java Web学习系列——Maven Web项目中集成使用Spring
参考Java Web学习系列——创建基于Maven的Web项目一文,创建一个名为LockMIS的Maven Web项目. 添加依赖Jar包 推荐在http://mvnrepository.com/.h ...
- Java web 学习之旅
java web学习之旅 来公司十天了,感觉已经慢慢地融入了这个环境中,几个学长人都很好,都是在他们帮助下,我才能比较顺利的开始了学习java web的旅途. 来这里学习的第一个阶段是做一个简单的用户 ...
随机推荐
- php面试专题---14、Linux基础考点
php面试专题---14.Linux基础考点 一.总结 一句话总结: php考linux其实也考不了很难 1.系统定时任务? crontab命令和 at命令 crontab命令 crontab -e ...
- WebGIS常用代码集锦
一.普通代码 1.坐标转换 ol.proj.transform(coordinate, source, destination) ol.proj.transform(coordinate, 'EPSG ...
- 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 ...
- inline-block的间隙问题 box-orient属性 line-clamp属性 margin问题
只要设了 display:inline-block 将元素变成行级块元素的时候,会自带空隙,即使你设了 margin 和 padding 依然没有效果! 解决办法:只要在父元素上加上font-size ...
- fread fwrite文本模式读写回车换行符 自动转换问题
fread 会把\r\n(0d0a)替换为\nfwrite 会把\n替换为\r\n(0d0a),\r\n会变成\r\r\n(0d0d0a) 今天在写一个日志类,用于打印服务程序的信息. 我将每一个日 ...
- Flask-SQLALchemy动态的filter_by和filter
1.filter_by filter_by用于查询简单的列名,不支持比较运算符. filters = {'name': 'fengyao', 'age': 26} User.query.filter_ ...
- 本站CSS代码
body { /*字体样式*/ font-family: "youyuan",幼圆,"MicrosoftJhengHei",华文细黑,STHeiti,MingL ...
- Java Web项目启动执行顺序
一. 1.启动一个WEB项目,WEB容器会先去读取它的配置文件web.xml,读取<context-param>和<listener>两个节点. 2.接着,容器创建一个Serv ...
- jmeter对响应数据做断言
单独校验某个接口中的某个字段时,断言就相当于检查点 添加http请求,输入路径url
- IDF-CTF-牛刀小试 writeup
题目链接:http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=16 被改错的密码 从前有一个熊孩子入侵了一个网站的数据库, ...