使用JDBC CallableStatements
执行存储过程
CallableStatement的所有超级接口为PreparedStatement、Statement、Wrapper。其中继承自PreparedStatement接口。CallableStatement主要是调用数据库中的存储过程。在使用CallableStatement时可以接收存储过程的返回值。CallableStatement对象为所有的DBMS提供了一种标准的形式去调用数据库中已存在的存储过程。对数据库中存储过程的调用是CallableStatement对象所含的内容。有两种形式:1:形式带结果参数;2:形式不带结果参数。结果参数是一种输出参数(存储过程中的输出OUT参数),是存储过程的返回值。两种形式都有带有数量可变的输入、输出、输入和输出的参数。用问号做占位符。
形式带结果参数语法格式:{ ? = call 存储过程名[(?, ?, ?, ...)]};
形式不带结果参数语法格式:{ call 存储过程名[(?, ?, ?, ...)]};PS方括号里面的内容可有可无。
CallableStatement接口中常用的方法。
1:getInt(int parameterIndex)、getInt(String parameterName)、还有getString、getBigDecimal、getString、getDate、getURL等等都类似和PreparedStatement与Statement中的用法类似。
2:registerOutParameter(int parameterIndex, int sqlType):按顺序位置parameterIndex将OUT参数注册为JDBC类型sqlType。
3:wasNull():查询最后一个读取的OUT参数是否为SQL Null。等等还有很多方法,感兴趣的读者可以自行查阅JDK API文档。
讲解了那么多,不如一个例子来的痛快。下面通过一个例子让读者更清楚的看到CallableStatement的用法。
首先在原先的t_employee表中添加表示干了多少年的tyear字段。
1 alter table t_employee add tyear int;
在数据库中编写存储过程统计指定id的userName的人,输出一下他一共赚了多少钱。
JDBC代码:
1 package com.panli.dbutil; 2 /** 3 * 连接数据库 4 */ 5 import java.sql.CallableStatement; 6 import java.sql.Connection; 7 import java.sql.DriverManager; 8 import java.sql.PreparedStatement; 9 import java.sql.ResultSet; 10 import java.sql.SQLException; 11 import java.sql.Statement; 12 13 public class DbUtil { 14 //数据库驱动名字 15 private static String jdbcName = "com.mysql.jdbc.Driver"; 16 //数据库协议地址 17 private static String dbUrl = "jdbc:mysql://localhost:3306/db_user"; 18 //数据库用户名 19 private static String dbUser = "root"; 20 //数据库密码 21 private static String dbPassword = "123456"; 22 23 24 /** 25 * 获取连接 26 * @return 27 * @throws Exception 28 */ 29 public static Connection getCon() throws Exception{ 30 Class.forName(jdbcName); 31 Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword); 32 return conn; 33 } 34 35 /** 36 * 关闭连接 37 * @param stmt 38 * @param conn 39 * @throws Exception 40 */ 41 public static void close(Statement stmt,Connection conn) throws Exception{ 42 if(stmt!=null){ 43 stmt.close(); 44 if(conn!=null){ 45 conn.close(); 46 } 47 } 48 } 49 50 /** 51 * 关闭连接 52 * @param cstmt 53 * @param conn 54 * @throws Exception 55 */ 56 public static void close(CallableStatement cstmt, Connection conn) throws Exception{ 57 if(cstmt!=null){ 58 cstmt.close(); 59 if(conn!=null){ 60 conn.close(); 61 } 62 } 63 } 64 65 66 /** 67 * 关闭连接 68 * @param pstmt 69 * @param conn 70 * @throws SQLException 71 */ 72 public static void close(PreparedStatement pstmt, Connection conn) throws SQLException{ 73 if(pstmt!=null){ 74 pstmt.close(); 75 if(conn!=null){ 76 conn.close(); 77 } 78 } 79 } 80 81 82 /** 83 * 重载关闭方法 84 * @param pstmt 85 * @param conn 86 * @throws Exception 87 */ 88 public void close(ResultSet rs,PreparedStatement pstmt, Connection conn) throws Exception{ 89 if(rs!=null){ 90 rs.close(); 91 if(pstmt!=null){ 92 pstmt.close(); 93 if(conn!=null){ 94 conn.close(); 95 } 96 97 } 98 } 99 100 } 101 }
1 package com.panli.model; 2 3 import java.io.File; 4 5 /** 6 * model包下的cemployee类,对每个字段进行建模 7 * @author Peter 8 * 9 */ 10 public class CEmployee { 11 private int id; 12 private String userName; 13 private double salary; 14 private String job; 15 private int jobTypeId; 16 private File context; 17 private File pic; 18 private double counts; 19 /** 20 * 默认的构造方法 21 */ 22 public CEmployee() { 23 super(); 24 // TODO Auto-generated constructor stub 25 } 26 27 /** 28 * 带一个参数的构造方法 29 * @param id 30 */ 31 public CEmployee(int id) { 32 super(); 33 this.id = id; 34 } 35 36 /** 37 * 两个参数的构造方法 38 * @param counts 39 * @param userNames 40 */ 41 public CEmployee(double counts, String userName) { 42 // TODO Auto-generated constructor stub 43 this.counts = counts; 44 this.userName = userName; 45 } 46 47 /** 48 * 重写toString()方法 49 */ 50 @Override 51 public String toString(){ 52 return userName+"一共赚了"+counts+"钱"; 53 } 54 public int getId() { 55 return id; 56 } 57 public void setId(int id) { 58 this.id = id; 59 } 60 public String getUserName() { 61 return userName; 62 } 63 public void setUserName(String userName) { 64 this.userName = userName; 65 } 66 public double getSalary() { 67 return salary; 68 } 69 public void setSalary(double salary) { 70 this.salary = salary; 71 } 72 public String getJob() { 73 return job; 74 } 75 public void setJob(String job) { 76 this.job = job; 77 } 78 public int getJobTypeId() { 79 return jobTypeId; 80 } 81 public void setJobTypeId(int jobTypeId) { 82 this.jobTypeId = jobTypeId; 83 } 84 85 public File getContext() { 86 return context; 87 } 88 89 public void setContext(File context) { 90 this.context = context; 91 } 92 93 public File getPic() { 94 return pic; 95 } 96 97 public void setPic(File pic) { 98 this.pic = pic; 99 } 100 101 public double getCounts() { 102 return counts; 103 } 104 105 public void setCounts(double counts) { 106 this.counts = counts; 107 } 108 109 }
1 package com.panli.dao; 2 3 import java.sql.CallableStatement; 4 import java.sql.Connection; 5 import java.sql.Types; 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import com.panli.dbutil.DbUtil; 10 import com.panli.model.CEmployee; 11 12 public class CountsEmployeeDao { 13 private static DbUtil dbUtil = new DbUtil(); 14 /** 15 * 调用存储过程得到指定ID用户的一共赚了多少钱 16 * @param employee 17 * @return 18 * @throws Exception 19 */ 20 public static List getCountsById(CEmployee cemployee)throws Exception{ 21 List list = new ArrayList(); 22 Connection conn = dbUtil.getCon(); 23 String sql = "{call pro_getCountById(?, ?, ?)}"; 24 CallableStatement cstmt = conn.prepareCall(sql); 25 cstmt.setInt(1, cemployee.getId()); 26 cstmt.registerOutParameter(2, Types.DOUBLE); 27 cstmt.registerOutParameter(3, Types.VARCHAR); 28 cstmt.execute(); 29 double counts = cstmt.getDouble("counts"); 30 String userNames = cstmt.getString("userNames"); 31 CEmployee emp = new CEmployee(counts, userNames); 32 list.add(emp); 33 dbUtil.close(cstmt, conn); 34 return list; 35 } 36 /** 37 * 做测试的主方法 38 * @param args 39 */ 40 public static void main(String[] args)throws Exception { 41 42 CEmployee cemployee = new CEmployee(1); 43 List list = getCountsById(cemployee); 44 for(CEmployee cemp: list){ 45 System.out.println(cemp); 46 } 47 } 48 }
创建的存储过程为:
1 delimiter && 2 create procedure pro_getCountById(in tid int, out counts double, out userNames varchar(20)) 3 begin 4 select salary*tyear into counts from t_employee where id = tid; 5 select userName into userNames from t_employee where id = tid; 6 end 7 && 8 9 测试: 10 call pro_getCountById(1, @counts, @userNames); 11 select @counts, @userNames;