使用java原生jdbc完成数据的增删改查
在开始这篇博文之前要对上一篇博文中出的一个小错误进行说明,在遍历查询的结果集始我使用了map.put(“firstname”,rs.getString(“first_name”).toUpperCase());这种写法,而实际的写法应该是map.put(“firstname”,rs.getString(“first_name”.toUpperCase()));原来的写法在intellij中可以正常运行,但是查询的结果转为大写了,但是出现这个问题后不知道能不能在MyEclipse下运行,在我的记忆中要获取结果集的字段值应该是需要使用大写的字段名的。在这里就不做专门的验证了,等下次有MyEclipse中遇到类似的功能在做验证。
接下来开始今天的正文,今天的这个小实例是承接上次的小项目,前台使用html标签(之所以选择这种方式展示数据是因为在添加点击事件的方式比较简单)展示测试数据。后台使用的是jdbc来操作oracle数据库。还是先来贴一张项目的截图。
在本文的最下方,我会将今天的小实例提供下载,如果有需要的可以直接下载,而在本文内容中就不在贴完整代码了,仅仅贴出核心的代码提供讲解而已。
项目运行的界面
核心代码1
<%--
Created by IntelliJ IDEA.
User: leo
Date: 2016/9/17
Time: 15:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String path = request.getContextPath();
String context = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<title>展示页面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="-1">
<script type="text/javascript" src="jslib/jquery-1.11.2.min.js"></script>
<script type="text/javascript">
var global = null;
$(function(){
debugger;
$.ajax({
url:"<%=context%>queryServlet",
dataType:"json",
success:function(data){
global=data;
$("#display").html("");
$("#display").append("<tr> <th>employee_id</th> <th>first_name</th> <th>last_name</th> <th>email</th> <th>phone_number</th> <th>hire_date</th> <th>salary</th> <th>operator</th> </tr>");
for(var i in data){
$("#display").append("<tr> <td>"+data[i].employeeid+"</td> <td>"+data[i].firstname+"</td> <td>"+data[i].lastname+"</td> <td>"+data[i].email+"</td> <td>"+data[i].phonenumber+"</td> <td>"+data[i].hiredate+"</td> <td>"+data[i].salary+"</td> <td><a href="#" onclick="update("+i+")">update</a>|<a href="#" onclick="add()">add</a>|<a href="<%=context%>deleteServlet?employeeid="+data[i].employeeid+"">delete</a></td> </tr>");
}
}
});
})
function update(index) {
alert(global[index].employeeid);
$("#addOrUpate").html("");
$("#addOrUpate").html("<form action="<%=context%>updateServlet">"
+"<input type="hidden" name="employeeid" value=""+global[index].employeeid+"">"
+"first_name:<input type="text" name="firstname" value=""+global[index].firstname+""><br>"
+"last_name:<input type="text" name="lastname" value=""+global[index].lastname+""><br>"
+" email:<input type="text" name="email" value=""+global[index].email+""><br>"
+" phone_number:<input type="text" name="phonenumber" value=""+global[index].phonenumber+""><br>"
+"hire_date:<input type="text" name="hiredate" value=""+global[index].hiredate+""><br>"
+"salary:<input type="text" name="salary" value=""+global[index].salary+""><br>"
+"<input type="submit" value="Submit">"
+"</form>"
);
}
function add() {
$("#addOrUpate").html("");
$("#addOrUpate").html("<form action="<%=context%>insertServlet">"
+"first_name:<input type="text" name="firstname"><br>"
+"last_name:<input type="text" name="lastname"><br>"
+" email:<input type="text" name="email"><br>"
+" phone_number:<input type="text" name="phonenumber"><br>"
+"hire_date:<input type="text" name="hiredate"><br>"
+"salary:<input type="text" name="salary"><br>"
+"<input type="submit" value="Submit">"
+"</form>"
);
}
</script>
</head>
<body>
<h2>使用html原生表格标签来展示数据</h2>
<table id="display" border="1" cellspacing="0" cellpadding="3">
</table>
<div id="addOrUpate">
</div>
</body>
</html>
在前台页面中使用for循环遍历json数据,将后台返回的数据拼接成html语言,为了在修改信息的时候能够定位需要修改的信息,需要将每条数据的index传给Update(),而且这种传值方式只能传简单类型。我有尝试将一个数组对象作为参数传给Update(),但是没有成功。所以最后定义了一个全局变量,然后通过index来获取需要修改的数据。
核心代码2
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>com.leo.servlet.Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/queryServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UpdateServlet</servlet-name>
<servlet-class>com.leo.servlet.UpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UpdateServlet</servlet-name>
<url-pattern>/updateServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>InsertServlet</servlet-name>
<servlet-class>com.leo.servlet.InsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InsertServlet</servlet-name>
<url-pattern>/insertServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DeleteServlet</servlet-name>
<servlet-class>com.leo.servlet.DeleteServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DeleteServlet</servlet-name>
<url-pattern>/deleteServlet</url-pattern>
</servlet-mapping>
</web-app>
在web.xml中要配置需要访问的路径,这种方式相当繁琐,在以后我们使用struts2,spring mvc就会发现简单很多了,servlet的配置直接交给框架来完成。
核心代码3
package com.leo.dao;
import com.leo.utils.DBUtil;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
- company:**数码技术股份有限公司
- Created by leo on 2016/9/17.
*/
public class Dao {
public Connection getConnection() throws Exception{
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","leo","leo");
return conn;
}
public List<Map<String, Object>> selectUserData() throws Exception{
Connection conn = getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "select employee_id,first_name,last_name,email,phone_number,hire_date,salary from employees ORDER BY employee_id";
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
List<Map<String,Object>> list = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
while (rs.next()){
Map<String,Object> map = new HashMap<>();
map.put("employeeid",rs.getString("employee_id".toUpperCase()));
map.put("firstname",rs.getString("first_name".toUpperCase()));
map.put("lastname",rs.getString("last_name".toUpperCase()));
map.put("email",rs.getString("email".toUpperCase()));
map.put("phonenumber",rs.getString("phone_number".toUpperCase()));
map.put("hiredate",sdf.format(rs.getDate("hire_date".toUpperCase())));
map.put("salary",rs.getLong("salary".toUpperCase()));
list.add(map);
}
new DBUtil().close(rs,ps,conn);
return list;
}
public String updateUserDate(String employeeid, String firstname, String lastname, String email, String phonenumber, String hiredate, String salary) throws Exception {
Connection conn = getConnection();
Statement stat = null;
String sql = "update employees set first_name = ""+firstname+"" , last_name = ""+lastname+"" , email = ""+email+"" , phone_number = ""+phonenumber+"" , hire_date = to_date(""+hiredate+"","yyyy-MM-dd") , salary = "+salary+" where employee_id = ""+employeeid+""";
stat = conn.createStatement();
int i = stat.executeUpdate(sql);
new DBUtil().close(null,stat,conn);
if(i>0){
return "success";
}
return "error";
}
public String addUserDate(String firstname, String lastname, String email, String phonenumber, String hiredate, String salary) throws Exception {
String idSql = "select EMPLOYEES_SEQ.nextval as id from dual";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date(sdf.parse(hiredate).getTime());
Connection conn = getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
ps = conn.prepareStatement(idSql);
rs = ps.executeQuery();
rs.next();
int employeeid = rs.getInt("ID");
String sql = "insert into employees(employee_id,first_name,last_name,email,phone_number,hire_date,salary) values(?,?,?,?,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setInt(1,employeeid);
ps.setString(2,firstname);
ps.setString(3,lastname);
ps.setString(4,email);
ps.setString(5,phonenumber);
ps.setDate(6,date);
ps.setLong(7,Long.parseLong(salary));
int i = ps.executeUpdate();
new DBUtil().close(rs,ps,conn);
if(i>0){
return "success";
}
return "error";
}
public String removeUserDate(String employeeid) throws Exception {
String sql = "delete from employees where employee_id = ""+employeeid+""";
Connection conn = getConnection();
PreparedStatement ps =null;
ps = conn.prepareStatement(sql);
int i = ps.executeUpdate();
new DBUtil().close(null,ps,conn);
if(i>0){
return "success";
}
return "error";
}
}
这就是这个小实例操作数据库的代码,里面包括几个需要关注的点。
- PreparedStatement和Statement的使用。
- oracle如何实现主键的自增长
- PreparedStatement的预加载
- 数据库的资源管理
先说以第一个,在这个小实例中我只是展示了PreparedStatement和Statement的使用,PreparedStatement相对于Statement有一个优势,那就是PreparedStatement可以不用通过拼接sql来查询,这样就省去了类型转换的问题,就像在修改用户信息的时候,我们需要对date类型的数据进行转换,而在添加用户的时候只需要将一个date类型的数据直接赋给对应的位置即可。
第二个,我们都知道oracle的主键增长是通过sequence来实现,这个sequence可以直接在数据库中创建,但是在使用时不能像MySql那样方便,网上有很多使用sequence的方法,我在本实例中使用的是最常用的一种方式,即先通过一条sql语句将sequence的下一个值查询出来,获取到这个值并随着数据一起插入到数据库中。
第三个,就像在第一个问题里说到的,预加载能够解决类型转换的问题,这种方式提高了安全性,降低了sql注入的风险,具体的编写方式参考代码中的实现即可。
第四个,在使用原生jdbc一定要注意打开的连接在使用完以后要关闭,如果数据操作频繁,而又没有及时的关闭已经使用的连接,很有可能造成资源的浪费,甚至是影响程序的执行。在本实例写了一个专门的类来关闭已经使用过的资源。
在本实例中还有一个值得注意的知识点,就是在数据库执行完毕后,我们需要根据数据库的执行情况来跳转页面,这里我使用的是重定向的方式来跳转的,还有一种方式是转发的方式。至于这两个的用法和区别以后有机会再说。以下是修改数据成功后的跳转代码。
package com.leo.servlet;
import com.leo.service.Service;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* company:**数码技术股份有限公司
* Created by leo on 2016/9/20.
*/
@WebServlet(name = "UpdateServlet")
public class UpdateServlet extends HttpServlet {
private Service service = new Service();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String employeeid = request.getParameter("employeeid");
String firstname = request.getParameter("firstname");
String lastname = request.getParameter("lastname");
String email = request.getParameter("email");
String phonenumber = request.getParameter("phonenumber");
String hiredate = request.getParameter("hiredate");
String salary = request.getParameter("salary");
String result = service.modifyUserDate(employeeid,firstname,lastname,email,phonenumber,hiredate,salary);
if("success".equals(result)){
response.sendRedirect("index.jsp");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
数据库的表结构和序列
create table EMPLOYEES
(
employee_id NUMBER(6) not null,
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
phone_number VARCHAR2(20),
hire_date DATE,
salary NUMBER(8,2)
)
-- Create sequence
create sequence EMPLOYEES_SEQ
minvalue 1
maxvalue 9999999999999999999999999999
start with 207
increment by 1
nocache;
这篇博客涉及的完整项目在这里下载
- 上一篇: C++全局常量与变量的定义方法
- 下一篇: JDBC那些事(四)——原生JDBC的一些缺陷