Oracle之实战(图书馆系统)java源代码部分

看这文章之前,最好先看 Oracle之实战(图书馆系统)中对应的数据库脚本,里面定义了表空间,用户,授权,存储过程,触发器,序列,数据表等。

这里主要讲解怎么在java代码中使用这些数据库对象,这里主要使用jdbc的api。

表空间和用户:

在已经创建好表空间和用户后,我们就需要在java代码中连接数据库,这里我把连接数据库的操作封装成一个工具类:文件名:JdbcUtils.java,对应的内容为:

package com.lrz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public final class JdbcUtils {
private static String driver = "oracle.jdbc.driver.OracleDriver";//Oracle驱动,记得往工程里面加入相应的驱动包,不然会包ClassNotFound的错误
private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";//orcl是安装oracle时安装的数据库实例,1521是这个数据库实例占用的端口号
private static String username = "lrz";//在oracle中已经创建好的用户,并且该用户已经取得所需的授权
private static String password = "916520";//用户密码

private JdbcUtils() {}//作为工具类,对外提供静态方法,所以声明构造方法为私有,外部就不能new了

//加载数据库驱动,只需要加载一次,所以将其放置在静态代码块中,如果加载驱动都不成功,其他所有的数据库操作都无法进行,

//所以我们必须知道加载驱动是否成功,不成功,就应该主动抛出例外,好让我们自己哪里出错了。
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
//获取数据库连接,这里的connection跟数据库中的会话,或者hibernate中的session会话,

//可以理解成同一概念,hibernate中的session其实内部就封装了一个connection
public static Connection getConnection() throws SQLException {

//这里的DriverManager相当于hibernate中的sessionfactory
return DriverManager.getConnection(url, username, password);
}

//关闭连接数据库操作对象,结果集,提一下数据库连接的原则,尽量晚获取数据库连接,尽量早释放数据库连接

//为什么呢?数据库连接,说白了底层就是socket通讯,建立通讯线路需要花费很多时间,对于高并发操作数据库来说

//这种消耗就显得特别大。所以我们学习hibernate的时候,会尽量使用数据源(连接池)技术,这样就可有效的使用数据库连接

//而且hibernate都是将数据库操作押后,hibernate成为懒加载,其实也就充分利用一次连接做更多的事情(增删查改)
public static void free(ResultSet rs, Statement st, Connection conn) {
try {//想想有没有比这种关闭方式更合理的吧,这个来说算比较合理的关闭了
if (rs != null){
rs.close();
rs = null;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null){
st.close();
st = null;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
conn = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}


查询一条唯一记录的java代码:

public BookType getById(int id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
BookType bookType = null;
try {
conn = JdbcUtils.getConnection();

//是否注意到这里的sql语句可以使用问号占位符呢,所以代码中没使用普通的Statement对象

//而是获取了PreparedStatement 数据库操作对象
String sql = "select * from tb_bookType where id=?";
ps = conn.prepareStatement(sql);

//为sql语句的问号占位符赋值,这里的setInt就是说设置一个整型数值,这种类型是跟我在数据库表中定义id这个字段的类型(number)是一致的

//当然你的数据库字段的类型是别的类型,如varchar2,就可以使用setString了,对于oracle的字段数据类型和java中数据类型的对应关系,也挺多东西讲得

//有空我会整理一下,提一下,这个下标是从1开始的,我记得第一个参数也可以根绝数据库表中的字段名设置值,如setInt("id",id),不过记得不是十分清楚了
ps.setInt(1, id);
rs = ps.executeQuery();

//一开始查询出来的游标是这样的:游标指针位于 “第一条记录前” 这个位置,每rs.next()一次,游标指针都向后一条记录移动

// 第一条记录前 第一条记录 第二条记录 第三条记录 ... 最后一条记录 最后一条记录后

//由于我的id是唯一确定一条记录的,所以查询出来的结果集也只有一次记录,所以这个while循环只会next两次,但只有移动到唯一的记录才为真
while(rs.next()){
bookType = new BookType();
bookType.setId(rs.getInt(1));
bookType.setName(rs.getString(2));
bookType.setDays(rs.getInt(3));
bookType.setFine(rs.getFloat(4));
}
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);//dao层如果有例外,主动跑出,在其他层就可以捕获
}finally{
JdbcUtils.free(rs, ps, conn);
}
return bookType;
}


查找多条记录(结果集,游标)的请款

跟查询一条的代码只有微微变动,由于我的书籍类型记录不是很多,需求中也要查询出全部,我在这里就没有使用到分页功能

public List queryAll(){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
BookType bookType = null;
List list = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from tb_bookType";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
list = new ArrayList();
while(rs.next()){
bookType = new BookType();
bookType.setId(rs.getInt(1));
bookType.setName(rs.getString(2));
bookType.setDays(rs.getInt(3));
bookType.setFine(rs.getFloat(4));
list.add(bookType);
bookType = null;
}
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(rs, ps, conn);
}
return list;
}



增加一条记录:

public int add(BookType bookType){
Connection conn = null;
PreparedStatement ps = null;
int result = -1;
try {
conn = JdbcUtils.getConnection();

//bookType_id.nextval?bookType_id是我在oracle数据库建好的序列,oracle主要用来实现主键自增长,nextval设置自增长得下一个值
String sql = "insert into tb_bookType(id ,name , days , fine) values(bookType_id.nextval,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, bookType.getName());
ps.setInt(2, bookType.getDays());
ps.setFloat(3, bookType.getFine());
result = ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(null, ps, conn);
}
return result;
}


//删除一条记录

public int delete(int id) {
Connection conn = null;
PreparedStatement ps = null;
int result = -1;
try {
conn = JdbcUtils.getConnection();

//主要就是sql语句有点不同
String sql = "delete from tb_bookType where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, id);

//result是指该数据库操作影响的记录数据
result = ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(null, ps, conn);
}
return result;
}



//更新记录

public int update(BookType bookType) {
Connection conn = null;
PreparedStatement ps = null;
int result = -1;
try {
conn = JdbcUtils.getConnection();

//也主要是sql有点不同而已
String sql = "update tb_bookType  set name=?,days=?,fine=? where id=?";
ps = conn.prepareStatement(sql);
ps.setString(1, bookType.getName());
ps.setInt(2, bookType.getDays());
ps.setFloat(3, bookType.getFine());
ps.setInt(4, bookType.getId());
result = ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(null, ps, conn);
}
return result;
}



操作oracle中定义好的存储过程:

public List queryAll() {
Connection conn = null;

//之前我们都是使用Statement或PreparedStatement数据库操作对象

//这里使用CallableStatement才能操作oracle中的存储过程
CallableStatement  proc = null;
ResultSet rs = null;
Order order = null;
List list = null;
try {
conn = JdbcUtils.getConnection();

//lrz是用户名,oracle中的用户名可以简单理解成schema(架构名),PROCEDURE_ORDER_BKINFO是在oracle中定义好的存储过程

//存储过程定义了一个传出参数,参数类型使用了包去定义成游标类型

String sql = "{ call lrz.PROCEDURE_ORDER_BKINFO(?) }";
proc = conn.prepareCall(sql);

//oracle存储过程的传外参数时,java中要注册对应的数据类型来接收数据

//oracle中定义了游标类型,java代码中也使用游标类型与之对应,注意.OracleTypes这个类,里面定义了很多类型常量
proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
proc.execute();
rs = (ResultSet)proc.getObject(1);//游标,对应上jdbc就是结果集,这里进行强转一下就好
list = new ArrayList();
while(rs.next()){

//按照数值下标,感觉比较麻烦
order = new Order();
order.setId(rs.getInt(9));
order.setBkISBN(rs.getString(1));
order.setOperaterNo(rs.getString(11));
order.setAccount(rs.getInt(12));
order.setOrderDate(rs.getTimestamp(13));
order.setCheckAndAccept(rs.getString(14));
order.setDiscount(rs.getInt(15));

order.setBkTypeId(rs.getInt(2));
order.setBkInfoName(rs.getString(3));
order.setBkInfoAuthor(rs.getString(4));
order.setBkInfoTranslator(rs.getString(5));
order.setBkInfoPublisher(rs.getString(6));
order.setBkInfoPublishDate(rs.getTimestamp(7));
order.setBkInfoPrice(rs.getFloat(8));
list.add(order);
order = null;
}
} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(rs, proc, conn);
}
return list;
}


还是操作存储过程:

只是这个存储过程定义的参数是输入参数(传内)

public void add(Order order) {
Connection conn = null;
CallableStatement  proc = null;
try {
conn = JdbcUtils.getConnection();
String sql = "{ call lrz.PROCEDURE_ORDER_1(?,?,?,?,?) }";
proc = conn.prepareCall(sql);

//传内参数,只需要赋值就可
proc.setString(1, order.getBkISBN());
proc.setString(2, order.getOperaterNo());
proc.setInt(3, order.getAccount());
proc.setTimestamp(4, order.getOrderDate());
proc.setFloat(5, order.getDiscount());
proc.execute();


} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(null, proc, conn);
}
}


还是存储过程:

两个参数,一个传外,一个传内,Types与前面的OracleTypes都是jdbc中获取类型常量的类,只是OracleTypes是针对oracle数据库的

public int update(int orderId) {
Connection conn = null;
CallableStatement  proc = null;
int result = -1;
try {
conn = JdbcUtils.getConnection();
String sql = "{ call lrz.PROCEDURE_ORDER_2(?,?) }";
proc = conn.prepareCall(sql);
proc.setInt(1, orderId);
proc.registerOutParameter(2, Types.INTEGER);

result = proc.executeUpdate();


} catch (SQLException e) {
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(null, proc, conn);
}
return result;
}



触发器:

Oracle之实战(图书馆系统)中定义了一个触发器,即删除 图书类别记录,就会删除 图书信息表中 类别相同的 所有书籍记录

所以java代码中只要删除 图书类别记录,oracle数据库就会执行这个触发器。


下面说说分页查询功能:

在mysql中,实现分页功能使用limit关键字

如:

select * from emp limit 9,10;

需要注意的是,mysql中的记录号是从0开始的,所以第十条记录编号为9

limit 9,10?9代表从第(9+1)条记录开始查,查询10条记录

limit 9,-L?9代表从第(9+1)条记录开始查,-L代表查询到最后一条记录

那么在oracle中怎么实现分页查询呢?

关键字 rownum

如:select * from scott.emp where rownum <= 10;// 查询出前10条记录


那能不能 select * from scott.emp where rownum >= 5 and rownum <= 10;  ?????//不能

或者select * from scott.emp where rownum between 5 and 10;

结果查询不出数据,到官方文档一看,就晓得了。

官方文档关键语句Conditions testing for ROWNUM values greater than a positive integer are always false.

那我们可以这样:

select empno,ename,job,mgr,hiredate,sal,comm,deptno from (select  empno,ename,job,mgr,hiredate,sal,comm,deptno,rownum as num from emp) where num between 6 and 10;

这样就实现分页查询了,对于分页查询,我有空也得写具体些。



你可能感兴趣的:(Oracle)