Oracle数据库部分终于在昨天结束了,整理学习日志到很晚。今天继续讲解JDBC,是方老师授课的。方老师在我们班还有六堂的课程,多少有些舍不得,他是个好老师。学完这六堂课,JAVAWEB基础到此也就结束了( 09-12-18 )。十分渴望快些学习到项目那,把这些技术混合运用,做出个像模像样的东西来!
今天的内容依然很多,我还是好好把它整理出来吧!
一、JDBC中调用Oracle存储过程:
例,在Oracle中创建一个存储过程:
CREATE OR REPLACE PROCEDURE UPEMPFUN( ARG_EMPNO IN NUMBER, ARG_SAL IN NUMBER, ARG_RES OUT VARCHAR )IS BEGIN UPDATE EMP SET SAL = ARG_SAL WHERE EMPNO=ARG_EMPNO; COMMIT; ARG_RES := 'OK!'; END; |
在JDBC中,调用上面的存储过程(我的Oralce出问题了,没有测试):
CallableStatement cStmt = conn.prepareCall("{call UPEMPFUN(?, ?, ?)}"); // 注册接收返回值的变量 cStmt.registerOutParameter(3, Types.VARCHAR); cStmt.setInt(1, 7360); cStmt.setFloat(1, 8888); cStmt.execute(); // 打印返回值 System.out.println(cStmt.getString(3)); |
二、JDBC数据库中的分布技术:
1.ResultSet提供了对结果集进行滚动的功能:
next():移动到下一行
Previous():移动到前一行
absolute(int row):移动到指定行
beforeFirst():移动resultSet的最前面
afterLast() :移动到resultSet的最后面
使用上面的滚动记录功能可以实现分页功能,但建议不要使用这种技术进行分页。因为当记录数量大的时间,会带来性能上的下降,资源的浪费。
2.MySQL分页语句:
Select * from tab_ame limit M,N;
M:记录起始索引位置
N:获取记录数量
3.Oracle分页语句(TOP-N技术):
Select * from (
Select rownum rn,* from (
Select * from tab_name where 条件
) where rownum <=结束位置
)where rn >=起始位置
它与MySql分页相比,MySql更方便些。而且MySql中的N直接获取记录数量,但Oracle中却是结束位置的索引和起始位置的索引之间的记录。
4.编写一个WEB应用,使用分布技术显示数据库中的记录:
简易流程图:(如果看不到图片,请到这里:http://www.blogjava.net/changcheng/)
ListStudent.java,doGet部分:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取总记录数量 StudentDao sd = new StudentDao(); int totalrecord = 0; int pagenum = 0; Page page = null; try { totalrecord = sd.getTotal(); // 获取记录信息 String currage = request.getParameter("currpage"); page = new Page(totalrecord, (currage != null) ? Integer .parseInt(currage) : 1); page.setRecord(sd.getRecord(page.getStartindex(), page.getPagesize())); } catch (Exception e) { e.printStackTrace(); }
// 将信息发往index.jsp进行显示 request.setAttribute("page", page); request.getRequestDispatcher("index.jsp").forward(request, response); } |
Student.java:
public class StudentDao { // 获取学生总数 public int getTotal() throws SQLException { // 获取连接 Connection conn = JdbcUtil.getDataSource().getConnection(); // 查询数量 PreparedStatement ps = conn .prepareStatement("select count(*) from student"); ResultSet rs = ps.executeQuery(); int total = 0; while (rs.next()) { total = rs.getInt(1); } // 释放连接 JdbcUtil.release(rs, ps, conn); return total; }
// 获取记录 public List getRecord(int startindex, int count) throws SQLException { // 获取连接 Connection conn = JdbcUtil.getDataSource().getConnection(); // 查询记录 PreparedStatement ps = conn .prepareStatement("select id,name,sex from student limit ?,?;"); ps.setInt(1, startindex); ps.setInt(2, count); ResultSet rs = ps.executeQuery(); // 读取记录 List result = new ArrayList(); while (rs.next()) { StudentBean stuben = new StudentBean(); stuben.setId(rs.getInt("id")); stuben.setName(rs.getString("name")); stuben.setSex(rs.getBoolean("sex")); result.add(stuben); } // 释放连接 JdbcUtil.release(rs, ps, conn); return result; }
} |
Page.java:
public class Page { private int totalrecord;// 总记录数 private int totalpage;// 总页面数 private int pagesize = 3;// 页面显示记录数 private int startindex;// 起始索引 private int currpage;// 当前页面 private List record;// 记录
public Page(int totalrecord, int currpage) { this.totalrecord = totalrecord; this.currpage = currpage; } public int getTotalrecord() { return this.totalrecord; } public List getRecord() { return record; } public void setRecord(List record) { this.record = record; } // 计算总页面数 public int getTotalpage() { if (this.totalrecord % this.pagesize == 0) totalpage = this.totalrecord / this.pagesize; else totalpage = this.totalrecord / this.pagesize + 1;
return this.totalpage; } // 计算起始索引 public int getStartindex() { this.startindex = (this.currpage - 1) * this.pagesize; return this.startindex; } public int getPagesize() { return this.pagesize; } } |
Index.jsp,body部分:
<body> HI <hr> <table border="1"> <tr> <td>ID</td><td>姓名</td><td>性别</td> </tr> <!-- 显示记录信息 --> <cc:forEach var="record" items="${page.record}"> <tr> <td>${record.id }</td><td>${record.name }</td><td>${record.sex }</td> </tr> </cc:forEach>
<!-- 显示翻页信息 --> </table> <cc:forEach var="i" begin="1" end="${page.totalpage}"> <a href="http://localhost:8080/091210/ListStudent?currpage=${i}">${i}</a> </cc:forEach> </body> |
如果连接的是Oracle数据库,则使用Oracle数据库的TOP-N技术即可!
三、JDBC对数据库LOB操作:
LOB数据(LargeObject),简称大对象。它分为两类:
1. CLOB:CharactorLargeObject,专门用于处理字符的大对象。
2. BLOB:ByteLargeObject,专门用于处理二进制数据,比如图片等。
1. MySQL中的LOB操作:
在MySQL中:TEXT与CLOB对应,BLOB与BLOB对应。
调用下面的方法设置TEXT:
PreparedStatement.setCharacterStream(index, reader, length); //注意length长度须设置,并且设置为int型 |
调用下面的方法获取TEXT:
1.reader = resultSet. getCharacterStream(i); 2.reader = resultSet.getClob(i).getCharacterStream(); 3.string = resultSet.getString(i); |
调用下面的方法设置BLOB:
PreparedStatement.setBinaryStream(i, inputStream, length); |
调用下面的方法获取BLOB:
1.InputStream in = resultSet.getBinaryStream(i); 2.InputStream in = resultSet.getBlob(i).getBinaryStream(); |
在MySql数据库中使用LOB字段,直接定义这个字段的类型为“TEXT”或“BLOB”即可!
2. Oracle中的LOB操作:
在Oracle中CLOB与“EMPTY_CLOB()”对应,“BLOB”与“EMPTY_BLOB()”对应。
Oracle中设置和获取BLOB的JDBC方法与MySQL相同。
在Oralce中添加LOB字段插入内容时,必须在事件中进行否则极可能出错。
注意:在Oracle数据库中添加CLOB字段必须使用“empty_clob()”,添加BLOB字段必须使用“empty_blob()”。在对他们进行赋值时,必须使用查询语句获取对应字段名的指针。在获取字段指针的查询语句结尾必须使用“fro update”这样锁定该行,保证不会发生冲突。
例,向Oracle数据库写入大文本操作:
private static void save() throws Exception { // 获取连接 Connection conn = JdbcUtil.getDataSource().getConnection(); conn.setAutoCommit(false); PreparedStatement ps = conn .prepareStatement("insert into ocolb(id, text) values (1,empty_clob())"); ps.executeUpdate(); // 获取指针 ps = conn.prepareStatement("select text from ocolb where id=1 for update;"); ResultSet rs = ps.executeQuery(); // 写入数据 File imfi = new File("C:/ocolb.txt"); Reader reader = new FileReader(imfi); //ps.setCharacterStream(1, reader, imfi.length()); CLOB clob = (CLOB) rs.getClob("text"); Writer writer = clob.getCharacterOutputStream(); char[] buf = new char[1024]; int len = 0; while((len = reader.read(buf)) != -1){ writer.write(buf, 0, len); } reader.close(); writer.close(); // 提交 conn.commit(); // 释放连接 JdbcUtil.release(rs, ps, conn); } |
四、JDBC对数据库批量操作:
当我们向数据库的一个表中插入100条记录时,比如向employee表中插入100名员工。难道我们要一条条语句执行?如果插入100万条呢?后果可想而知,所以需要批量操作来完成此任务。
在JDBC中有两种方法可以进行指操作:
1. Statement.addBatch(sql):
实现批处理的缺点:当向表中使用sql语句批量插入数据时,采用此种方式需重复写上多条语句相同,只参数不同的sql语句,工作量大,可读性差。
String sql1 = "insert into employee(id,name) values(1,'aaa')"; String sql2 = "insert into employee(id,name) values(2,'bbb')"; st = conn.createStatement(); st.addBatch(sql1); st.addBatch(sql2); st.executeBatch(); |
2. PreparedStatement. addBatch():
SQL语句相同,但参数相同。此种方法主要用于在同一个表中批量插入数据、或批量更新数据。
String sql2 = "insert into employee(name,department_id) values(?,?)"; ps = conn.prepareStatement(sql2); Iterator it = department.getEmployees().iterator(); while(it.hasNext()){ Employee e = (Employee) it.next(); ps.setString(1, e.getName()); ps.setInt(2, id); ps.addBatch(); } |
五、JDBC操作多个实体:
操作多个实体?这个玩法第一次听说。说直白些就是将JAVA对象与数据库的表,关联起来。如何关联?当然是通过代码关联了。
例:
1.创建department和employee表:
Create table department( id int primary key auto_increment, name varchar(50) )
Create table employee( id int primary key auto_increment, name varchar(30), department_id int, constraint for_ke foreign key(department_id) references department(id) ) |
2.定义Department和Employee类:
public class Department { private int id; private String name; private Set<Employee> employees = new HashSet<Employee>(); … }
public class Employee { private int id; private String name; private Department department; … } |
3.创建一个多Department对象,创建多个个Employee对象,添加到Department对象的SET中。
4.定义一个工具类,将Department对象给工具类的SAVE方法,SAVE方法使用批量操作,将数据添加到数据库的department和employee表中。
注意:
JAVA里边无论对象和对象之间什么关系,反应到数据库中就是外键关联。
在应用设计中尽量不要使用一对多的关系或多对多关系,而是使用多对一的关系。
整理日志比较辛苦,加油!