网站建设知识
【java】对数据库操作的那些事(包括数据库中的预处理)
2025-07-22 09:58  点击:0

一、连接问题

前面刚介绍了怎么连接数据库,也写了相应的模板,但是它的可维护性非常差,那么怎么解决这个问题呢?

首先写一个配置文件jdbc.properties

## MySQLdriver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/hncu?useUnicode=true&characterEncoding=UTF-8username=rootpassword=1234## Oracle#driver=oracle.jdbc.driver.OracleDriver#url=jdbc:oracle:thin:@192.168.31.12:1521:orcl#username=scott#password=tiger

然后创建一个生成连接的工厂ConnFactory .java
package cn.hncu.hibernate0;import java.io.IOException;import java.sql.Connection;import java.sql.DriverManager;import java.util.Properties;public class ConnFactory {private static Connection conn;static {try {//读取配置文件Properties p = new Properties();p.load(ConnFactory.class.getClassLoader().getResourceAsStream("jdbc.properties"));String driver = p.getProperty("driver");String url = p.getProperty("url");String username = p.getProperty("username");String pwd = p.getProperty("password");Class.forName(driver);conn = DriverManager.getConnection(url,username,pwd);System.out.println("已连接到数据库..."+conn);} catch (Exception e) {throw new RuntimeException("读取配置文件失败", e);}}public static Connection getConn(){return conn;}public static void main(String[] args) {getConn();}}
最后直接通过ConnFactory.getConn()获得。这要做的好处,当改变所要连接的数据库类型时,只需要修改配置文件中的内容即可。

二、讲解getXXX()方法

@Testpublic void getXXXDemo() throws Exception{Statement st = ConnFactory.getConn().createStatement();String sql = "select * from book";ResultSet rs = st.executeQuery(sql);while(rs.next()){Integer id = rs.getInt(1);//这里的1表示数据表中的第一列,下面同理String name = rs.getString(2);//Double price = (Double)rs.getObject(3);//出异常,因为内部是采用BigDecimal来处理Double price = rs.getDouble(3);Object dateTime = rs.getObject(4);//把日期和时间作为一个整体读取出来System.out.println(id+","+name+","+price+","+dateTime);String strDateTime = dateTime.toString();System.out.println(strDateTime);strDateTime = rs.getDate(4)+"--"+rs.getTime(4);//日期和时间可以单独获取System.out.println(":::"+strDateTime);}ConnFactory.getConn().close();}
注:对于自动增长列,删除之后再插入新记录,序号不会回头,继续往前增长。即中间会出现空号

三、讲解Statement中的三个executeXXX()方法

1、executeQuery: 只能执行select语句

2、executeUpdate: 可以执行insert、delete和update语句,但不能执行select

3、execute:增删改查的4种(任意)语句都能执行。该方法若执行非select语句时返回false,执行select语句时返回true,且st对象会缓存该次查询的结果,我

们可通过ResultSet rs = st.getResultSet()来获得结果集

@Testpublic void executeXXXDemo() throws Exception{Statement st = ConnFactory.getConn().createStatement();    String sql = "select * from book";//String sql = "insert into book(name,price,pub) values('软件工程',22.35,'2015-12-05 22:12:23')";//String sql = "update book set price=38.88 where name='软件工程'";//String sql = "delete from book where name='软件工程'";    //st.executeQuery(sql);//st.executeUpdate(sql);boolean boo = st.execute(sql);if(boo){ResultSet rs = st.getResultSet();while(rs.next()){System.out.println(rs.getObject(2));}}}

四、数据库查询时防黑技术(预处理语句)

案例、用户登录(通过用户输入信息来拼接sql语句----很危险)

@Test//用户登录    public void login() throws Exception{Connection con = ConnFactory.getConn();Statement st = con.createStatement();Scanner sc = new Scanner(System.in);int id = sc.nextInt(); sc.nextLine();String name = sc.nextLine();String sql = "select count(*) from stud where id="+id+" and sname='"+name+"'";System.out.println("sql:"+sql);ResultSet rs = st.executeQuery(sql);rs.next();int a = rs.getInt(1);if(a<=0){System.out.println("登录不成功");}else{System.out.println("登录成功");}con.close();   }
黑的方法,输入:1002(回车) 1' or '1'='1
因此:如果需要用 用户输入的信息 来拼接 sql语句,就不能用statement,否则用户可以通过构建where子句中的一个true条件来突破防护对于上面的情

况,应该用PreparedStatement来解决!

@Test//用户登录     黑:1002(回车)   1' or '1'='1public void login2() throws Exception{Scanner sc = new Scanner(System.in);Connection con = ConnFactory.getConn();String sql = "select count(*) from stud where id=? and sname=?";//需要用户输入的地方,用占位符('?')来代替,然后在后续通过设参来给占位符赋值PreparedStatement pst = con.prepareStatement(sql);//设置参数int id = sc.nextInt(); sc.nextLine();pst.setInt(1, id); //参数1----代表第1个占位符String name = sc.nextLine();pst.setString(2, name);//参数2ResultSet rs = pst.executeQuery();rs.next();int a = rs.getInt(1);if(a<=0){System.out.println("登录不成功");}else{System.out.println("登录成功");}con.close();   }

五、获取自动增长列(如id)

@Test //演示获取自动增长列如idpublic void saveAuto() throws Exception{Connection con = ConnFactory.getConn();String sql = "insert into book(name,price,pub) values('JavaEE',100.8,'2013-06-12 08:30:30')";Statement st = con.createStatement();//st.executeUpdate(sql);st.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);ResultSet rs = st.getGeneratedKeys();//里面封装了自动生成的所有值if(rs.next()){int id = rs.getInt(1);//获取第1个自动增长列System.out.println("自动增长的id:"+id);}System.out.println("-----------------");//预处理语句sql =  "insert into book(name,price) values(?,?)";PreparedStatement pst = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);pst.setString(1, "计算机基础");pst.setDouble(2, 28);pst.executeUpdate();ResultSet rs2 = pst.getGeneratedKeys();//里面封装了自动生成的所有值if(rs2.next()){int id = rs2.getInt(1);//获取第1个自动增长列System.out.println("自动增长的id:"+id);}}


六、演示批处理语句

public void batch() throws Exception{Connection con = ConnFactory.getConn();String sql = "insert into book(name,price,pub) values('JavaEE',100.8,'2015-06-12 08:30:30')";Statement st = con.createStatement();for(int i=0;i<10;i++){st.addBatch(sql);}sql = "update book set price=price*1.1 where price>100";st.addBatch(sql);int[] a = st.executeBatch();for(int r:a){System.out.println(r);//r为每条sql语句所影响的记录数}}

预处理
public void preparedBatch() throws Exception{Connection con = ConnFactory.getConn();String sql = "insert into book(name,price,pub) values(?,?,?)";PreparedStatement pst = con.prepareStatement(sql);for(int i=0;i<5;i++){pst.setString(1, "Java"+i);pst.setDouble(2, 55.85+i);pst.setString(3, "2016-12-10 07:07:08");pst.addBatch(); //pst的方式不能带参数sql}//pst.executeBatch();int[] a = pst.executeBatch();for(int r:a){System.out.println(r);//r为每条sql语句所影响的记录数}}

注意:预处理的方式不能带参数sql,普通的需要