JDBC
JDBC
jdbc的目标是使java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统
Java应用程序——>JDBC API——>JDBC驱动程序——>数据库
Java.sql.Driver接口是所有JDBC驱动程序需要实现的接口。
》这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现
》在程序中不需要直接访问实现了Driver接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现
数据库厂商必须实现的接口,能从中获取数据库的连接
/** * JDBC URL * jdbc:mysql://localhost:3306/test * * 对于oracle数据库连接: * jdbc:oracle:thin:@localhost:1521:sid * * 对于SQLserver数据库连接: * jdbc:miscrosoft:sqlserver//localhost:1433;DatabaseName=sid * * 对于MYSQL数据库连接: * jdbc:mysql://localhost:3306/sid */
连接数据库的步骤:
1、注册驱动(只做一次)
2、建立连接(Connection)
3、创建执行SQL的语句(Statment)
4、执行语句
5、处理执行结果(ResultSet)
6、释放资源
DriverManager 是驱动的管理类
1)可以通过重载的getConnection()方法获取数据库连接,较为方便
2)可以同时管理多个驱动程序:若注册多个数据库连接,则调用getConnection()方法时传入的参数不同,即返回不同的数据库连接
String driverClass = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@localhost:1521:orcl"; String user = "scott"; String password = "123456"; //加载数据库驱动程序(对应的Driver实现类中有注册驱动的静态代码块) //DriverManager.registerDriver((Driver) Class.forName(driverClass).newInstance()); Class.forName(driverClass); Connection conn = DriverManager.getConnection(url, user, password); System.out.println(conn);
通过配置文件jdbc.properties获取数据库连接
String driverClass = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@localhost:1521:orcl"; String user = "scott"; String password = "123456"; //读取配置文件信息 InputStream is = getClass().getClassLoader().getResourceAsStream("jdbc.properties"); Properties pro = new Properties(); //将读取的配置文件信息传入pro pro.load(is); //根据值进行查询赋值 driverClass = pro.getProperty("driverClass"); url = pro.getProperty("url"); user = pro.getProperty("user"); password = pro.getProperty("password"); //创建一个驱动对象 Class.forName() 加载数据库驱动 Driver driver = (Driver) Class.forName(driverClass).newInstance(); Properties info = new Properties(); info.put("user",user); info.put("password",password); //通过driverManager的getConnection()方法获取连接 Connection conn = DriverManager.getConnection(url, info); return conn;
*增、删、改用Statement.executeUpdate来完成,返回整数(匹配的记录数),这类操作相当简单。
*查询用Statement.executeQuery来完成,返回的是ResultSet对象,ResultSet中包含了查询的结果。
创建与数据库的连接的标准方式是在
DriverManager上调用方法getConnection().
statement(语句对象)
》executeUpdate(String sql):
执行SQL insert,update或delete语句,返回受影响的行的数目或零;返回值为int型
》executeQuery(String sql)
执行返回单个ResultSet的SQL语句;返回类型ResultSet
》execute(String sql)
执行可以返回多个结果的SQL语句。返回类型boolean,如果返回的是更新的数目,则返回false,如果返回ResultSet,则返回true。(不常用)
//1.获取数据库连接 Connection conn = getConnection(); //2.准备插入的sql语句 String sql = "insert into student values(3,'123','123')"; //3.执行插入 //(1)获取操作与SQL语句的Statement对象 Statement state = conn.createStatement(); //(2)调用Statement对象的executeUpdate(sql)执行SQL语句进行插入 int result = state.executeUpdate(sql); System.out.println(result); //4.关闭Statement对象 state.close(); //5.关闭连接 conn.close();
PreparedStatement
* 使用PreparedStatement
* 1)why?
①使用statement需要进行拼写SQL语句。很辛苦,而且容易出错。
②可以有效地禁止SQL注入。
——SQL诸如是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入,数据中注入非法的SQL语句段
——对于Java而言,要规范SQL注入,只要用PreparedStatement取代Statement就可以了。
SQL注入
String username = "a' OR PASSWORD = "; String password = "OR '1' = '1"; String sql = "SELECT * FROM USERS WHERE USERNAME = '" + username + "' AND " + "PASSWORD = '" + password + "'"; } select * from users where username = 'a' or password = 'and password = ' or '1' = '1'
《3》PreparedStatement能最大可能提高性能
* 2)PreparedStatement:是Statement的子接口,可以传入带占位符的SQL语句,而且
* 提供了补充占位符变量的方法。
*
* 使用PreparedStatement
* ①创建PreparedStatement:
* String sql = "INSERT INTO STUDENT VALUES(?,?,?,?,?)"
* PreparedStatement ps = conn.prepareStatement(sql);
*
* ②调用PreparedStatement的setXxx(int index,Object val)设置占位符的值。
* index值从1开始
*
* 3执行SQL语句:executeQuery()或executeUpdate().注意:执行时不再需要传入SQL语句
@Test public void test2(){ Connection conn = null; PreparedStatement preparedStatement = null; try { conn = getConnection(); String sql = "insert into examstudent values(?,?,?,?,?,?,?)"; preparedStatement = conn.prepareStatement(sql); preparedStatement.setInt(1,11); preparedStatement.setInt(2, 2); preparedStatement.setString(3, "43121223113"); preparedStatement.setString(4,"1245523"); preparedStatement.setString(5,"yhs"); preparedStatement.setString(6,"dwd"); preparedStatement.setInt(7,3); int re = preparedStatement.executeUpdate(); if(re ==1){ System.out.println("插入成功!!!"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ release(preparedStatement, conn, null); } }
ResultSet
结果集读取数据的方法主要是getXXX(),他的参数可以使整数表示第几列(从1开始的),还可以是列名。
返回的是对应的XXX类型的值。如果对应那列时空值,XXX是对象的话返回XXX型的空值,如果XXX是数字类型,如Float等返回0,boolean返回false
结果集,封装了使用JDBC进行查询的结果
1.调用Statement对象的executeQuery(sql)可以得到结果集
2.ResultSet返回的实际上就是一张数据表,有一个指针指向数据表的第一行的前面
可以使用next()方法检测下一行是否有效,若有效该方式返回true,且指针下移。
相当于Iterator对象的hasNext()和next()方法的结合体
3.当指针对位到一行时,可以通过getXxx(index)或getXxx(columnName)
获取每一列的值,例如:getInt(1),getString("name")
4.ResultSet:当然也需要进行关闭
单条数据查询:
Connection conn = getConnection(); Statement state = conn.createStatement(); String sql = "select * from student where id=1"; ResultSet rs = state.executeQuery(sql); if(rs.next()){ int id = rs.getInt(1); String name = rs.getString("name"); String password = rs.getString("password"); System.out.println(id); System.out.println(name); System.out.println(password); } conn.close(); state.close(); rs.close();
多条数据查询:
Connection conn = getConnection(); Statement state = conn.createStatement(); String sql = "select * from student"; ResultSet rs = state.executeQuery(sql); while(rs.next()){ int id = rs.getInt(1); String name = rs.getString("name"); String password = rs.getString("password"); System.out.print(id + " "); System.out.print(name + " "); System.out.println(password); } conn.close(); state.close(); rs.close();
封装查询多个对象的方法:
ResultSetMetaData:(解决红色部分)接口
1)what:是描述ResultSet的元数据对象,即从中可以获取到结果集有多少列,列名是什么....
2) how:
<1>得到ResultSetMetaData 对象:调用ResultSet的getMetaData()方法
<2>ResultSetMetaData有哪些好用的方法
>int getColumnCount(): SQL语句包含哪些列
>String getColumnLabel(int column):获取指定的列的别名,其中索引从1开始。
获取结果集每一列的别名
for(int i=0;i<rsmd.getColumnCount();i++){
String columnLabel = rsmd.getColumnLabel(i+1);
}
public <T> T testResultSetMetaData(Class<T> clazz,String sql,Object...args){ Connection conn = null; PreparedStatement preparedstatement = null; ResultSet resultset = null; T entity = null; try { conn = getConnection(); preparedstatement = conn.prepareStatement(sql); //对sql占位符进行赋值 for(int i=0;i<args.length;i++){ preparedstatement.setObject(i+1,args[i]); } resultset = preparedstatement.executeQuery(); ResultSetMetaData metaData = resultset.getMetaData(); Map<String,Object> map = new HashMap<String,Object>(); while(resultset.next()){ for(int i=0;i<metaData.getColumnCount();i++){ String columnLabel = metaData.getColumnLabel(i+1); Object obj = resultset.getObject(i+1); map.put(columnLabel, obj); System.out.println(columnLabel + " " +obj); } } if(map.size()>0){ entity = clazz.newInstance(); //遍历Map对象,利用反射为Class对象对应的属性赋值 for(Map.Entry<String, Object> entry : map.entrySet()){ String fieldName = entry.getKey(); Object value = entry.getValue(); BeanUtil } } } catch (Exception e) { // TODO: handle exception }finally{ release(preparedstatement, conn, resultset); } return null; }