Java JDBC的基础知识(四)
之前学习了如何创建一个数据库工具类,如下:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { // 私有化构造方法 private DBUtil() { } private static String url = ""; private static String user = ""; private static String password = ""; private static String className = ""; static { try { Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 得到連接 public static Connection getConn() { @SuppressWarnings("unused") Connection conn = null; try { conn = DriverManager.getConnection(url, user, password); } catch (SQLException e) { e.printStackTrace(); } return null; } // 关闭连接 public static void close(ResultSet rs, Statement stm, Connection conn) { if (rs != null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if (stm != null) { try { stm.close(); } catch (Exception e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } } }
现在主要是学习如何使用这个工具类。简单了解CURD的实现过程。
在百度百科中关于CURD是这样解释的:
CURD是一个数据库技术中的缩写词,一般的项目开发的各种参数的基本功能都是CURD。作用是用于处理数据的基本原子操作。
它代表创建(Create)、更新(Update)、读取(Retrieve)和删除(Delete)操作。CURD 定义了用于处理数据的基本原子操作。.之所以将CURD 提升到一个技术难题的高度是因为完成一个涉及在多个数据库系统中进行CRUD操作的汇总相关的活动,其性能可能会随数据关系的变化而有非常大的差异。CURD 操作通常是使用关系型数据库系统中的结构化查询语句(Structured Query Language,SQL)完成的。随着 Web 变得更加具有面向数据特性,因此需要从基于 SQL 的 CURD 操作转移到基于语义 Web 的 CURD 操作。
呃,一言以蔽之——增删改查。
一、增加操作
import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; //增加操作 public class Test3 { static int add(StuInfo stu) { int result = 0; Connection conn = null; Statement stm = null; try { conn = DBUtil.getConn(); stm = conn.createStatement(); String sql = "insert into stuInfo(name,age,shoolId) values('" + stu.getName() + "'," + stu.getAge() + "," + stu.getSchoolId() + ")";// 字符串类型不要忘记加单引号 result = stm.executeUpdate(sql);// 返回值代表数据库中受影响的行数 } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { DBUtil.close(null, stm, conn); } return result; } public static void main(String[] args) { StuInfo stu = new StuInfo(); stu.setName("阿三"); stu.setAge("25"); stu.setSchoolId(3); int result = add(stu); if (result > 0) { // 这里写result=1,编译通不过 System.out.println("操作成功"); } else { System.out.println("操作失败"); } } }
二、删除操作
//刪除操作 static int delStuById(int id){ int result=0; Connection conn=null; Statement stm=null; try{ conn=DBUtil.getConn(); stm=conn.createStatement(); String sql="delete from stuInfo where id=4"+id; result=stm.executeUpdate(sql); }catch(Exception e){ e.printStackTrace(); }finally{ DBUtil.close(null,stm,conn) } return result; }
三、更新操作
//更新操作 static int updateStudent(StuInfo stu) { int result = 0; Connection conn = null; Statement stm = null; try { conn = DBUtil.getConn(); stm = conn.createStatement(); String sql = "update stuInfo set name='" + stu.getName() + "',age=" + stu.getAge() + ",schoolId=" + stu.getSchoolId() + " where id=" + stu.getId() + " "; result=stm.executeUpdate(sql); } catch (Exception ex) { ex.printStackTrace(); } finally { DBUtil.close(null, stm, conn); } return result; }
四、查找操作
// 查询操作 static StuInfo getStuById(int id){ StuInfo stu=null; Connection conn=null; ResultSet rs=null; Statement stm=null; try{ conn=DBUtil.getConn(); stm=conn.createStatement(); String sql="select * from stuInfo where id="+id; rs=stm.executeQuery(sql); if(rs.next()){ stu=new StuInfo(); stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); stu.setAge(rs.getInt("age")); stu.setSchoolId(rs.getInt("schoolId")); } }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(rs,stm,conn); } return stu; }
查找出列表
//查询出列表 public static List<StuInfo> getAllStudent(){ List<StuInfo> stuList=new ArrayList<StuInfo>(); Connection conn=null; ResultSet rs=null; Statement stm=null; try{ conn=DBUtil.getConn(); stm=conn.createStatement(); String sql="select * from stuInfo " ; rs=stm.executeQuery(sql); while(rs.next()){ StuInfo stu=new StuInfo(); stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); stu.setAge(rs.getInt("age")); stu.setSchoolId(rs.getInt("schoolId")); stuList.add(stu); } }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(rs,stm,conn); } return stuList; } public static void main(String[] args) { List<StuInfo> stuList=getAllStudent(); for(int i=0;i<stuList.size();i++){ System.out.println(stuList.get(i)); } }
五、SQL 注入攻击
因为在给sql语句传参的时候,使用了字符串拼接的方式,所以导致了这种漏洞。
比如,注入串 : 1' or '1'='1,使得密码安全性缺失。
解决:
String sql="select * from admininfo where userName ='"+userName+"' and password='"+password+"' ";
六、PreparedStatement
在SQL中包含特殊字符或SQL的关键字(如: ' or 1 or ')时Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
PreparedStatement 是 从 Statement 扩展来的
优点:
1) 解决sql注入攻击
2) Statement 会使数据库频繁编译sql,可能造成数据缓冲区溢出
3) 数据库和驱动,可以对 PreparedStatement 进行优化
代码示例:
// 防注入的登录 public static AdminInfo getLoginAdmin(String userName,String password){ AdminInfo admin=null; Connection conn=null; ResultSet rs=null; PreparedStatement stm=null; //第一处 try{ conn=DBUtil.getConn(); String sql="select * from adminInfo where userName=? and password=?" ; //第二处:改成占位符表示 stm=conn.preparedStatement(sql);//第三处:注意,扩号里要传参,这条代码,要放在下面的两条之前 stm.setString(1,userName);//地四处:传参 stm.setString(2,password); rs=stm.executeQuery();//第五处:如果用preparedStatement,这里不要传参 if(rs.next()){ admin=new AdminInfo(); admin.setId(rs.getInt("id")); admin.setUserName(rs.getString("userName")); admin.setPassword(rs.getString("password")); admin.setAddress(rs.getString("address")); } }catch(Exception e){ e.printStackTrace(); }finally{ DBUtil.close(rs,stm,sonn); } return admin; }
六、几种常见的特殊类型
1).DATA,TIME,TIMESTAMP-> date,time,datetime
存:stm.setDate(i,d); stm.setTime(i,t); stm.setTimestamp(i, ts);
取:rs.getDate("birthday"); rs.getTime(i); rs.getTimestamp(i);
2).CLOB -> text
存:ps.setCharacterStream(index, reader, length);
ps.setString(i, s);
取:reader = rs. getCharacterStream(i);
reader = rs.getClob(i).getCharacterStream();
string = rs.getString(i);
3).BLOB -> blob
存:ps.setBinaryStream(i, inputStream, length);
取:rs.getBinaryStream(i);
rs.getBlob(i).getBinaryStream
演示1:日期类型
//日期類型 //java.sql.Date是java.util.Date的子类 public static int add(AdminInfo admin){ int result = 0; Connection conn = null; PreparedStatement stm = null; try { conn = DBUtil.getConn(); String sql="insert into adminInfo (userName,password,address, createDate,birthday) values (?,?,?,?,?) "; stm = conn.prepareStatement(sql); stm.setString(1, admin.getUserName()); stm.setString(2, admin.getPassword()); stm.setString(3, admin.getAddress()); //stm.setDate(4,admin.getCreateDate());//要的是子类,父类传不进去 stm.setDate(4, new java.sql.Date(admin.getCreateDate().getTime())); //可以用字符串类型处理data stm.setString(5, admin.getBirthday()); result=stm.executeUpdate(); } catch (Exception ex) { ex.printStackTrace(); } finally { DBUtil.close(null, stm, conn); } return result; } }
public static void main(String[] args) { AdminInfo admin=new AdminInfo(); admin.setUserName("阿三"); admin.setPassword("123"); admin.setAddress("杭州文一西路"); admin.setCreateDate(new Date()); admin.setBirthday("1999-03-05 12:20:40"); int result=add(admin); if(result>0){ System.out.println("成功"); }else{ System.out.println("失败"); } }
演示2:大文本处理
//将c盘的文件 index.html 读入数据库 static int addContent(){ int result=0; Connection conn=null; PreparedStatement stm=null; try{ conn=DBUtil.getConn(); String sql="insert into t_testclob (content) values (?)"; stm=conn.prepareStatement(sql); Reader br=new BufferedReader(new FileReader("c:\\index.html")); stm.setCharacterStream(1, br); result=stm.executeUpdate(); br.close(); }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(null, stm, conn); } return result; }
演示3:读文件并保存到指定位置
//把text类型的数据,读出来,存到e盘 static void getContent(){ Connection conn=null; PreparedStatement stm=null; ResultSet rs=null; try{ conn=DBUtil.getConn(); String sql="select * from t_testclob"; stm=conn.prepareStatement(sql); rs=stm.executeQuery(); while(rs.next()){ BufferedReader r=new BufferedReader(rs.getCharacterStream("content")); BufferedWriter bw=new BufferedWriter(new FileWriter("e:\\testxxx.txt")); String str=null; while((str=r.readLine())!=null){ bw.write(str); bw.newLine(); bw.flush(); } bw.close(); r.close(); } }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(null, stm, conn); } }
演示4:从数据库中读取图片
public static void getPhoto(){ ResultSet rs=null; Connection conn=null; PreparedStatement stm=null; try{ conn=DBUtil.getConn(); String sql="select * from t_testblob"; stm=conn.prepareStatement(sql); rs=stm.executeQuery(); int i=0; while(rs.next()){ // rs.getString("content"); InputStream in=rs.getBinaryStream("photo"); OutputStream out=new BufferedOutputStream(new FileOutputStream("e:\\test"+i++ +".bmp" )); byte [] buff=new byte[1024]; int len=0; while((len=in.read(buff))!=-1){ out.write(buff,0,len); } out.close(); in.close(); } }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(rs, stm, conn); } }
演示5:读一副图片到数据库
public static int addPhoto(){ int result=0; Connection conn=null; PreparedStatement stm=null; try{ conn=DBUtil.getConn(); String sql="insert into t_testblob (name,photo) values (?,?)"; stm=conn.prepareStatement(sql); InputStream in=new BufferedInputStream(new FileInputStream("c://bigPhoto.bmp")); stm.setString(1, "大头鬼"); stm.setBinaryStream(2,in); result=stm.executeUpdate(); in.close(); }catch(Exception ex){ ex.printStackTrace(); }finally{ DBUtil.close(null, stm, conn); } return result; }
附加:
图象或二进制文件 (Blob)
在mysql中,叫blob,在sqlserver中,叫 image 普通的blob 是64k。如果文件超过1M,则出现
Packet for query is too large (3781053 > 1048576). You can change this value on the server by setting the max_allowed_packet variable.
解决:
mysql 有一个系统参数 max_allowed_packet 默认值是 1048576(1M),
在my.ini中 , 找到 max_allowed_packet 它的值默认是 1M,可以将这个值调大。
演示六:使用配置文件
//在 DBUtil中设置 private static String url; private static String user; private static String password; private static String className; static{ try { //读取配置文件 Properties settings =new Properties(); InputStream in=new FileInputStream("src/dbconfig.properties"); settings.load(in); url=settings.getProperty("url"); user=settings.getProperty("user"); password=settings.getProperty("password"); className=settings.getProperty("className"); System.out.println(url); Class.forName(className); //加载驱动类 //如果不导jar包 Could not initialize class util.DBUtil } catch (ClassNotFoundException | IOException e) {//在Java核心基础1中介绍,可以这样做 throw new RuntimeException(e); } }