导读
今天的主要内容有:java 连接 Oracle,事务,Oracle 中的事务处理,Oracle 函数.
一,Java 连接 Oracle 的两种方式
第一种:桥连接(JDBC_ODBC)(不推荐)
1,准备工作:桥连接需要配置 ODBC 数据源,本机必须有安装了 Oracle 数据库.
步骤:打开控制面板 > 管理工具 > ODBC 数据源 > 添加 > 选择你安装的 Oracle 驱动程序:
测试一下:
如果用户名和密码没有错误,就会出现连接成功的标志!
2,使用 java 代码连接 Oracle 数据库
这些步骤几乎都是固定的,具体看代码即可:
package test;
import java.sql.*;
import org.junit.Test;
/*
* 使用JDBC_ODBC桥连接Oracle数据库.
*/
public class TestJDBC_ODBC {
@Test
public void test(){
try {
//1,加载驱动(注意:jdk1.8版本已经删除了这个驱动,如果要运行需要切换到其他版本)
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//2,获得连接(其中myOracle是数据源的名称,scott和tiger分别是要连接的账户和密码)
Connection conn = DriverManager.getConnection("jdbc:odbc:myOracle", "scott", "tiger");
//下面就是使用conn这个连接对象来操作数据库
//获得sql语句执行对象
Statement sm = conn.createStatement();
//执行sql语句并返回到结果集对象ResulSet中
ResultSet rs = sm.executeQuery("select * from emp");//查询emp表
//处理结果集:打印到控制台
while(rs.next()){
System.out.println("员工姓名:"+rs.getString(2));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
第二种:使用 JDBC 直接连接(推荐)
1,准备工作:导包.这种方式不需要配置数据源而是使用商家提供的 jar 包进行连接,而且支持远程连接,就是说本机不安装数据库也能连接到远程的数据库.
Oracle 不同的版本有不同的 jar 包,我们可以上网搜索,或者更简单的办法,打开安装目录就能找到相应 jar 包:(比如我的安装目录)
2,java 代码连接数据库
package test;
import java.sql.*;
import org.junit.Test;
//使用jdbc连接Oracle
public class Testjdbc {
@Test
public void test(){
try {
//1,加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2,获得连接(注:@后面写连接的ip地址,后面分别是Oracle默认端口号1521:数据库名称,账户名和密码)
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.183.1:1521:ORCL", "scott", "tiger");
//3,获得sql语句执行对象
Statement st = conn.createStatement();
//4,书写sql语句
String sql = "select * from emp";//查询emp表
//5,执行sql并将结果保存到结果集ResultSet中
ResultSet rs = st.executeQuery(sql);
//6,处理结果集
while(rs.next()){
System.out.println("员工姓名:"+rs.getString(2));//打印
}
//7,关闭资源
rs.close();
st.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果:
总结:很明显,jdbc 的连接方式更好,而桥连接不仅不支持远程连接,就连更新后的 jdk1.8 都删掉有 odbc 驱动包,所以尽量使用 jdbc 以减少不必要的麻烦.
二,子查询:补充内容
1,使用子查询插入数据
昨天的内容中我们使用子查询创建了新表,即:
--使用子查询创建新表
create table emp(eid,ename,sal) as select empno,ename,sal from emp;
这样的创表方式会将旧表中对应字段所有数据都更新到新表中,如果我们只需要工资大于 2000 的员工数据,除了删除数据我们还可以用子查询查入需要的数据:(相当于 values() 用 select 语句替换了)
--清空emp2表
trancate table emp2;
--使用子查询插入数据
insert into emp2(eid,ename,sal) select empno,ename,sal from emp where sal>2000;
2,使用子查询更新数据
同样的,除了插入数据,也能更新数据:(修改语句为:update 表名 set column1=value1,...where...,同样的我们将 Value 部分用 select 语句替代即可)
--将BLAKE的job,sal和comm改为和SMITH一样
update emp set (job,sal,comm) = (select job,sal,comm from emp where ename='SMITH') where ename='BLAKE';
三,Oracle 事务(Transaction)
1,事务的概念
事务机制是为了保证数据的一致性,由一组 DML(数据操作语言)语句组成,在一个事务中,这些语句要么全部失败,要么全部成功.
转账就是一个很典型的事务管理机制.比如张三给李四转账 1000 大洋,银行的转账业务处理过程大概可以分为两个步骤:1,从张三的账户减 1000 大洋;2,然后再往李四的账户加 1000 大洋.这两个过程对于数据库就相当于两句 DML 语句,一句是 update 张三的账户金额,另一句是 update 李四的账户金额.如果转账的时候顺顺利利是没什么问题的,关键在于如果在转账这一过程中出现了问题,比如李四的账号输错,变成了不存在的账号,那么张三的账户会扣掉 1000 大洋而李四的账户并不会收到转账,最终这 1000 大洋不翼而飞.
总而言之,为了保证数据的一致性(好比转账的这 1000 大洋),我们通常使用事务来管理数据库.上面的转账例子中,如果使用了事务,我们知道 DML 语句要么失败,要么成功 ,所以当无法转账到李四账户时第二条 update 语句失败,就会导致整个转账失败,进而之前的一切操作都变为无效.
2,事务的 4 个特性
原子性:说的是在一个事务内是不可分割的,要么成功,要么失败.
一致性:事务的前后数据的变化的一致性.
隔离性:是指事务之间互不干扰和影响,即并发执行事务时应当按照是连续地执行,互不干扰地执行 (一个接一个).(数据库可设置隔离级别,见下文).
持久性:简单说就是事务一旦执行成功就持久化到数据库中.
3,事务的隔离级别
事务的隔离级别从低到高有:(不同的隔离级别涉及不同的并发访问问题)
Read Uncommitted(读未提交):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果.所有的并发事务问题都可能会发生.
Read Committed(读已提交) :只有在事务提交后,其更新结果才会被其他事务看见.可以解决脏读问题.
Repeated Read(可重复读) :在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交.可以解决脏读,不可重复读.
Serialization(串行化) :理想的真正的事务隔离性,事务串行化执行,隔离级别最高,牺牲了系统的并发性.可以解决并发事务的所有问题.
4,隔离级导致的并发访问问题
脏读 (Drity Read):事务 A 修改了一个数据,但未提交,事务 B 读到了事务 A 未提交的更新结果,如果事务 A 提交失败,事务 B 读到的就是脏数据.
不可重复读 (Non-repeatable read) : 在同一个事务中,对于同一份数据读取到的结果不一致.比如,事务 B 在事务 A 提交前读到的结果,和提交后读到的结果可能不同.不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这导致锁竞争加剧,影响性能.
幻读(虚读)(Phantom Read) : 在同一个事务中,同一个查询多次返回的结果不一致.事务 A 新增了一条记录,事务 B 在事务 A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录.幻读仅指由于并发事务增加记录导致的问题,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁.需要将事务串行化,才能避免幻读.
四,Oracle 中的事务处理
1,相关概念
回滚:发送异常时,使数据恢复到事务开启前的状态,即整个事务执行失败.
提交:事务执行成功,数据会持久化到数据库.
2,基本演示
Oracle 中的事务默认是关闭的,所以需要手动开启事务,并设置回滚和提交的位置:
public void test(){
//Oracle事务案例:
Connection conn = null;
try {
//连接数据库
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.183.1:1521:ORCL", "scott", "tiger");
//-------[开启事务]:我们在执行sql前开启事务
conn.setAutoCommit(false);
//执行sql语句
Statement st = conn.createStatement();
String sql = "update emp set sal=sal-500 where ename='SMITH'";//将smith的工资降低500
st.executeUpdate(sql);
sql = "update emp set sal=sal+500 where ename='BLAKE'";//将blake的工资涨500
st.executeUpdate(sql);
} catch (Exception e) {
try {
//--------[回滚]:如果发生异常,说明事务执行失败,需要回滚
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
//------------[提交事务]:如果程序执行到最后,说明一切顺利,需要提交事务来持久化数据
try {
conn.commit();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
ps:在命令行中:我们也可以通过设置保存点 savepoint 达到开启事务的效果,用法如下:
3,只读事务:read only
说明:只读事务处理顾名思义,就是只能让用户进行读取(查询)操作.只读事务不只是限制作用,使用只读事务能确保用户读取某个时间点的数据,比如购票系统管理员需要每天 18 时开始统计售票情况,但可能在 18 时的时候任然有人在进行购票或退票的操作,这样统计出来的数据就不够准确,所以管理员可以在 18 时这个时间点设置只读事务,那么管理员就可以读取这个时间点的数据而不受其他并发操作的影响.所以只读事务常用于某个时间点的信息统计.
设置:sql > set transaction read only ;
五,Oracle 函数
1,字符函数
lower(char) :将字符串转化为小写
upper(char) :将字符串转化为大写
length(char) :获得字符串的长度
substr(char,m,n):截取字符串(从 1 标号)角标为 [m,n] 的子串.
--将员工姓名首字母大写,其余小写
select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename))) from emp;
replace(char,search_str,replace_str):字符串替换.
--假设员工名中的字母S需要用*和谐后才显示
select replace(ename,'S','*') from emp;
instr(char1,char2,[,n[,m]]):返回字符串 char2 在 char1 中首次出现的的位置.
--返回S在员工名字中首次出现的位置
select instr(ename,'S') from emp;
2,数学函数
数学函数的参数和返回值都是数字类型,数学函数包括:cos,cosh,exp,In,log,sin,sinh,sqrt,tan,tanh,acos,atan,asin,round 等,我们掌握常用的即可:
round(n [,m]):四舍五入数字 n:如果省略 m,那么四舍五入为整数;如果 m 是整数,则四舍五入到小数点后 m 位(相当于保留 m 位小数);如果 m 是负数,则四舍五入到小数点前 - m 位.
trunc(n [,m]): 截取数字 n:如果省略 m,那么就截取整数部分,即保留整数部分;如果 m 是整数,则截取到小数点后 m 位(相当于保留 m 位小数);如果 m 是负数,则截取到小数点前 - m 位.
mod(m,n) :取模.(取模运算和取余运算的数值是相同的,区别在于符号不同:取模运算结果的符号和除数的符号一致,而取余运算的符号和被除数的符号一致, 比如:10 模 -3 = -1;10 余 -3 = 1;).
floor(n) :floor 是地板的意思, 所以返回 ≤ n 的最大整数(向下取整).
ceil(n) :ceil 是天花板的意思,所以返回 ≥ n 的最小整数(向上取整).
abs(n) :返回绝对值.
3,日期函数
默认的 date 格式为:yy-mon-dd 即 18-1 月 - 23 的形式.
sysdate:返回系统时间
add_months(d,n):返回当前时间增加 n 个月后的时间.
--查找入职满3年的员工姓名
select ename from emp where sysdate>=add_months(hiredate,12*3);
--返回员工加入公司的天数(保留整数)
select ename,ceil(sysdate-hiredate) "入职天数" from emp;
last_day(d):返回指定日期所在月份的最后一天.
--查询入职月刚好最后一天入职的员工姓名和入职时间
select ename,hiredate from emp where hiredate = last_day(hiredate);
--查询入职月倒数前5天的员工姓名
select ename,hiredate from emp where hiredate >= last_day(hiredate)-4;
4,转换函数
转换函数是 Oracle 用来进行数据类型转换的函数,比如 number = 9527,就能转换为 char 类型.注意这个现象:比如我们往 emp 表中插入数据时,ename 即员工姓名是 vachar2 类型,但是如果我们插入时输入的值是数字,那么这个语句不会报错,因为 Oracle 在插入数据时会尝试将不匹配的数据类型进行转换,如果成功就继续插入,这就是 Oracle 隐含转换的一个例子.
有的转换函数需要指定转换后的格式,Oracle 格式符号规定如下:
to_char(data [,str_form]):将数据转换为 char 类型,第二个可选参数为格式.注意:对于数字格式如果输入错误会返回若干 #,代表转换失败.
--查询1980年入职的员工
select ename,hiredate from emp where to_char(hiredate,'yyyy')='1980';
to_date(str,form):将字符串为对应格式的日期.
to_number(date):将数据转换为 number 类型.
5,用户环境函数
userenv() 即用户环境函数,是 UserEnvironment 的缩写,用法:userenv('参数名'):返回用户所属环境的指定参数的参数值.
比如 select userenv('language') from emp; 就会返回 emp 表的环境语言.但 userenv 是一个遗留功能,这些功能是保留向后兼容性.甲骨文建议您使用 SYS_CONTEXT 函数使用内建的 USERENV 命名空间的当前功能.所以,我们尽量使用 sys_context('usernev','参数名') 来代替 userenv 函数.
参数名是固定可选的,常用的有以下几种参数名:
terminal :当前会话客户所对应的终端标识符.比如我的就是:LenovoPC.
language :语言.
db_name :数据库名.
nls_date_format:当前会话客户对应的日期格式.
session_user :当前会话客户对应的数据用户名.
current_schema:当前会话客户对应的默认方案名.(其实就是用户名,注意,一个用户对应一个方案,方案存储了很多数据对象)
host :返回数据库所在主机的名称.
来源: https://www.cnblogs.com/fzz9/p/8331825.html