您的位置:首页 > 数据库 > Oracle

深入浅出学Oracle&JDBC 之 第二部分:SQL(2)【私塾在线原创】

2012-02-29 11:49 375 查看

事务

事务是什么
用来维护数据库完整性,它保证成批的 SQL 要么全做,要么全不做。

1 、事务特性( ACID )事务必需满足 ACID ,缺一不可

原子性( Atomicity ):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
一致性( Consistency ):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态;
隔离性( Isolation ):并发事务执行之间无影响,在一个事务内部的操作对其他 事务是不产生影响,这需要事务隔离级别来指定隔离性;
持久性( Durability ):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因为如遇到系统故障或断电造成数据不一致或丢失。

事务处理
事务( transaction ):一组 SQL 语句;
回滚( rollback :撤销指定 SQL 语句的过程;
提交( commit :执行指定 SQL 语句;
保留点( savepoint ):事务处理中设置的临时占位符,可以对保留点执行回滚

示例如下:
delete from tbl_student;
commit;-- 提交事务,全部删除了

delete from tbl_student;
rollback;-- 回滚了事务,删除被撤销了

SQL实战

1 、不连续数谜题 : 找到表中没有的最小的 TBL_NUM num
Num
1
3
4
7
7
select min(num1.num+1) from TBL_NUM num1
where num1.num+1 not in (select num2.num from TBL_NUM num2);

2 、删除重复行 , 删除最先插入的
delete from tbl_num
where rowid not in (select max(rowid) from tbl_num group by num)

3 、分页

--3 、分页
select s2.* from
--2 、为检索出的数据加行号
(select s1.*, rownum r from
( --1 、最内层检索真正的数据
select * from tbl_student where 1=1
) s1
) s2
-- 分页条件
where s2.r>=1 and s2.r<3

分页三步曲:
1、检索记录
2、加行号
3、根据行号对结果分页



1 、检索张三所有孩子
Select * from tbl_tree where puuid=(select uuid from tbl_tree where name ='张三')
2 、检索张四的兄弟
Select * from tbl_tree where puuid=(select puuid from tbl_tree where name ='张四')
3 、检索张三的孙子
Select * from tbl_tree where puuid in (
select uuid from tbl_tree where puuid =(
select uuid from tbl_tree where name ='张三'))
4 、检索张三的孩子和孙子
Select * from tbl_tree where puuid=(select uuid from tbl_tree where name ='张三')
union
Select * from tbl_tree where puuid in (
select uuid from tbl_tree where puuid =(
select uuid from tbl_tree where name ='张三'))

5 、找张三的子子孙孙(包括重孙等)(递归查询)
select * from tbl_tree
where name!='张三‘
start with name='张三'
connect by prior uuid = puuid
--1 、递归开始:根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。 start with name= 张三 表示从张三开始
--2 、连接条件:[connect by] [prior] uuid = puuid,其中用prior表示上一条记录,比如 connect by prior uuid = puuid就是说上一条记录的uuid是本条记录的puuid,即前一条记录是当前记录的父亲。
--3 、递归方向: prior运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的顺序是自顶向下还是自底向上。
--4 、过滤条件:where子句,用于对返回的所有记录进行过滤

-- 加层次 level
select lpad(name, level*2+2,' ') from tbl_tree
connect by prior uuid = puuid
start with name='张三'

5 、前边递归做法是 oracle 特有的,再介绍个通用的 code ( 无递归 )
地区表

java代码:
create table TBL_AREA2
(UUID NUMBER not null,
NAME VARCHAR2(100),
CODE VARCHAR2(100),
constraint PK_AREA primary key (UUID),
constraint INDEX_AREA_CODE unique (CODE) using index);

insert into tbl_area2 values(1,'中国','01');
insert into tbl_area2 values(2,'上海','0101');
insert into tbl_area2 values(3,'深圳','0102');
insert into tbl_area2 values(4,'北京','0103');
insert into tbl_area2 values(5,'海淀','010301');
insert into tbl_area2 values(6,'朝阳','010302');


Code组成:由父的code+自己在兄弟里的大排名,每进入一层code长度加2
code列是唯一索引

6 、前边递归做法是 oracle 特有的,再介绍个通用的 code

1 、检索中国的孩子
Select * from tbl_area where code like '01__'
2 、检索中国的孙子
Select * from tbl_area where code like '01____'
3 、检索中国的子和孙(不包括重孙)
Select * from tbl_area where code like '01__' or code like '01____'
4 、检索中国的子孙(包括重孙)
Select * from tbl_area where code like '01__%'
5 、查询厂洼属于的城市 ( 不好向上递归,在 java 里做 )
Select * from tbl_area
where code =(select substr(code,0, 4) from tbl_area where name='厂洼')
6、查询厂洼所属城市的所有区
Select * from tbl_area
where code like (select substr(code,0, 4) || '__' from tbl_area where name='厂洼')

Oracle 递归支持和 Code 法比较
--1、puuid只有在Oracle里才好用,从通用性上来看code更好
--2.1、puuid number(10)
--2.2、code varchar2(100) 层数和一个父最多有多少个子有限制
--2.3、code列的规则一旦定下来很难改变
--3、移动节点(包括子节点)
puuid简单,只需更新父亲即可;
code麻烦,不仅需要更新父亲,连孩子都得修改;
oracle 内部支持法:把张四移到张五
update tbl_tree set puuid=(select uuid from tbl_tree where name='张五')
where name='张四';
code 法:如把北京移动到上海下边 ( 首先把北京移动到上海下,然后更新北京的孩子 )
update tbl_area set code='010101'||substr(code,5) where code like '0103%';

数据库设计优化



JDBC

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

能干什么?
标准的数据访问接口,可以连到不同的数据库;

发SQL查询字符串到数据库;

在Java应用程序中进行数据库的增删改查

有什么?
驱动程序 Driver
连接 Connection
语句 Statement/PreparedStatement





HelloWorld

1 、开发环境和运行环境准备
开发环境: java 工程 +oracle 数据库
运行环境: java SE+oracle 数据库
2 、准备 jar 包: ojdbc14.jar Oracle 驱动包)

3 、写客户端测试


java代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class ClientTest {

public static void main(String[] args) throws ClassNotFoundException {
//1. 注册加载一个 driver 驱动
Class. forName ("oracle.jdbc.driver.OracleDriver");
Connection conn = null;
try {
//2 创建数据库连接
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
String username = "test";
String password = "test";
conn = DriverManager. getConnection (url, username, password);
//3 创建一个 Statement (发送 sql )
Statement stat = conn.createStatement();
//4 执行 SQL
stat.execute("insert into tbl_student values(11,'zhang', 1, '1')");
//5 处理结果(无)
//5 关闭 Statement
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {//6 关闭连接
conn.close();
} catch (SQLException e) { e.printStackTrace(); }
}
}
}







Statement PreparedStatement 区别

1 PreparedStatement 能防止 SQL 注入问题,而 Statement 是动态拼出SQL ,因此不 能解决;

2 PreparedStatement SQL 进行预编译,因此如果我们采用绑定变量的SQL (语句 类似,数据不同)数据库只需解析一次(生成执行计划),因此效率要高;

3 Statement 由于没有采用绑定变量,因此可能每次都需要编译(生成执行计划),因 此对于那种语句类似但数据不同的 SQL 每次都需要编译,效率低;

4 PreparedStatement 开销要比 Statement 高, 因此如果 SQL 只执行一次,应该使用 Statement

5 、在大多数情况下都应该使用 PreparedStatement

java代码:
–Driver
–DriverManager
–Connection
–Statement
–PreparedStatement
–CallableStatement
–ResultSet
–DatabaseMetadata
–ResultSetMetadata
–Types


数据库元数据
数据库元数据和结果集元数据

1 DatabaseMetadata
使用conn.getMetadata方法获得;
提供了获取数据库相关数据信息的能力(如数据库对象)。

2 ResultSetMetadata
使用 ResultSet.getMetaData方法获得;
提供了各种方法去获得结果集元数据的相关数据信息,包括结果集的总行数

批量更新
批量更新,即一次提交多条同构更新操作语句给数据库
JDBC API 在批量更新之后只产生一个结果集对象
以下均支持批量更新
Statement
PreparedStatement
CallableStatement

Statement 批量更新

语法

java代码:
Statement  stmt = con.createStatement();
stmt.addBatch(sqlStr);


示例

java代码:
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.addBatch(“insert into tbl_users values(1, ‘z1’, 1, ‘1’)”);
stmt.addBatch(“insert into tbl_users values(2, ‘z2’, 1, ‘1’)”);
int[] results = stm.executeBatch();

con.commit();


PreparedStatement 批量更新
PreparedStatement 中使用批量更新时,一定要先设置好参数后,再使用addBatch() 方法加入缓存,最后一起发送到数据库。

语法

java代码:
PreparedStatement pstmt = con.prepareStatement(sqlStr);
pstmt.setXXX(..);
pstmt.addBatch();
pstmt.excuteBatch();


示例

java代码:
String sql = “ insert into tbl_student values(?,?,?,?) ” ;
PreparedStatement pstm = con.prepareStatement(sql);
pstm.setInt(1, 1); pstm.setString(2, “zhang1”);
pstm.setInt(3,1); pstm.setString(4,’1’);
pstm.addBatch();
int[] counts = pstm.excuteBatch(); con.commit();
Blob 和 Clob


1 、需要存储如图片、 word 文件等字节类型数据,请使用 Blob
2 、需要存储大文本数据,请使用 clob


java代码:
//1 、插入(通过 empty_clob() 来初始化 resourceValue )
String insertSql = "insert into tbl_resource" +
"(uuid, title, resourceValue) values(?,?, empty_blob() )";

PreparedStatement pstat = conn.prepareStatement(insertSql);
pstat.setInt(1, 1);
pstat.setString(2, "test");
pstat.executeUpdate();
pstat.close();
//2 、锁定要修改的数据行进行更新,注意 "for update" 语句
String selectForUpdateSql = "select resourceValue " +
"from tbl_resource where uuid=? for update";
pstat = conn.prepareStatement(selectForUpdateSql);
pstat.setInt(1, 1);

ResultSet rs = pstat.executeQuery();
// 读取 blob 数据
Blob blob = null;
if(rs.next()) {
blob = rs.getBlob("resourceValue");
}
// 将图片字节数据输出到 Blob 对象里

String fileName = "D:/Blue hills.jpg";
FileInputStream fis = new FileInputStream(fileName);
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
fis.close();

OutputStream os = blob.setBinaryStream(0);
os.write(bytes);
os.close();

pstat.close();
String selectSql = "select * from tbl_resource where uuid=?";
PreparedStatement pstat = conn.prepareStatement(selectSql);
pstat.setInt(1, 1);
ResultSet rs = pstat.executeQuery();
// 读取 blob 数据
if(rs.next()) {
String title = rs.getString("title");
Blob blob = rs.getBlob("resourceValue");
byte[] bytes = blob.getBytes(1, (int) blob.length());

File file = new File("D:\\Backup\\" + title + ".jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.close();
}
pstat.close();


Clob 新增 & 修改

java代码:
//1 、插入(通过 empty_clob() 来初始化 resourceValue )
String insertSql = "insert into tbl_content" +
"(uuid, title, content) values(?,?, empty_clob() )";
PreparedStatement pstat = conn.prepareStatement(insertSql);
pstat.setInt(1, 1);
pstat.setString(2, "test");
pstat.executeUpdate();
pstat.close();
Clob 新增 & 修改

//2 、锁定要修改的数据行进行更新,注意 "for update" 语句
String selectForUpdateSql = "select content " +
"from tbl_content where uuid=? for update";
pstat = conn.prepareStatement(selectForUpdateSql);
pstat.setInt(1, 1);

ResultSet rs = pstat.executeQuery();
// 读取 blob 数据
Clob clob = null;
if(rs.next()) {
clob = rs.getClob("content");
}
//3 、更新 Clob 内容
clob.setString(1, "test 中文 ");
pstat.close();
Clob 查询

String selectSql = "select content from tbl_content where uuid=?";
PreparedStatement pstat = conn.prepareStatement(selectSql);
pstat.setInt(1, 1);

ResultSet rs = pstat.executeQuery();
// 读取 C lob 数据
Clob clob = null;
if(rs.next()) {
clob = rs.getClob("content");
}

System. out .println(clob.getSubString(1, (int) clob.length()));

pstat.close();

视频配套PPT,视频地址【Oracle数据库开发及SQL基础视频原创内容 转自请注明【http://sishuok.com/forum/blogPost/list/0/3775.html#8875
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐