一、什么是JDBC
JDBC顾名思义是Java连接数据库,是一套规范(接口)那数据库厂商需要实现这套接口
//才能跟数据库建立连接,我们把数据库厂商写的这套实现类,称之为数据库驱动
二、API中与JDBC相关的接口和类(以及对应的方法)
CallableStatement 用于执行 SQL存储过程的接口
Result
三、JDBC连接数据库(初涉)
需求1:向数据库中插入一行数据
package org.westos.demo; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class JDBCTest { public static void main(String[] args) throws Exception { //1.导入MySQL数据库驱动jar包 //2.注册驱动 Class.forName("com.mysql.jdbc.Driver"); //3.获取连接对象,根据数据库建立连接 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123456"); //4.获取操作对象 Statement statement = conn.createStatement(); //定义sql语句 String sql = "insert into users values('zhaoliu','654321')"; //5.执行操作 statement.executeUpdate(sql); //释放资源 conn.close(); statement.close(); } }
说明:上面的太麻烦,每次都要进行修改;因此写成工具类并写成对应的配置文件(后续用c3p0进行连接)
工具类
package org.wzj.com; import java.io.FileReader; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; /** * 说明:自己写的连接工具类 * 原因:要了解底层,为以后底层开发打好基础 */ public class JDBCUtils { private static String password; private static String username; private static String url; //构造方法私有化 private JDBCUtils() { } static { //回顾属性集合类的作用和方法 Properties properties = new Properties(); try { //配置文件的方式进行读取,建立连接 properties.load(new FileReader("jdbc.properties")); } catch (IOException e) { e.printStackTrace(); } try { Class.forName(properties.getProperty("driverclass"));//注册(反射) } catch (ClassNotFoundException e) { e.printStackTrace(); } //建立连接三要素:(主协议、子协议、IP、端口、数据库)、用户名、密码 url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); } /** * * @return 连接数据库的对象 * @throws SQLException */ public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } /** * 功能:释放资源 * @param con * @param statement * @throws SQLException */ public static void close(Connection con, Statement statement) throws SQLException { if(con!=null){ con.close(); } if(statement!=null){ statement.close(); } } }
配置文件
driverclass=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test #如果是本地连接可以省略主机(ip)和端口号写成"///" username=root password=123456
Statement很容易出现sql注入(危险),因此采取预编译PreparedStatement
需求2:JDBC查询student用户表中的信息
package org.wzj.com; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JDBCTest { public static void main(String[] args) throws SQLException { Connection connection = JDBCUtils.getConnection(); //sql语句(重点掌握!!!) String sql ="select *from student "; //预编译(防止sql注入) PreparedStatement ps = connection.prepareStatement(sql); //注意:接受查询的数据是一个容器 ResultSet resultSet = ps.executeQuery(); while(resultSet.next()){ //常用根据列索引找值(从1开始) String s1 = resultSet.getString(1); String s2 = resultSet.getString(2); System.out.println(s1+","+s2); } JDBCUtils.close(connection,ps); } }
四、批处理
package org.wzj.com; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; /** * 说明:批处理 */ public class JDBCTest02 { public static void main(String[] args) throws SQLException { Connection connection = JDBCUtils.getConnection(); String sql="insert into user values(?,?)";//理解占位符的作用 PreparedStatement statement = connection.prepareStatement(sql); //创建一个集合(里面存储数据,然后批量增加) ArrayList<User> users = new ArrayList<User>(); User user=null; for(int i=1;i<=100;i++){ user= new User();//临时用户 user.setUsername("用户"+i); user.setPassword("密码"+i); users.add(user); } // 需求:批处理添加数据 //遍历集合插入数据 for(User u:users){ //对每个占位符进行赋值 statement.setString(1,u.getUsername()); statement.setString(2,u.getPassword()); // 笨办法--statement.executeUpdate();循环一条一条的插入,可以,但是效率不高 statement.addBatch();//添加到缓存中因为已经预处理过了,不需要写入sql语句了 } statement.executeBatch();//批处理(建立一个缓存,以免每次操作都需要连接) //清空批处理 statement.clearBatch(); //释放资源 JDBCUtils.close(connection,statement); } }
说明:
五、JDBC调用存储过程
存
package org.wzj.com; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import java.sql.Types; //说明:用Java代码调用存储过程 //需求:调用存储过程,查询数据的条数 public class JDBCTest03 { public static void main(String[] args) throws SQLException { //(1)倒包后建立数据库的连接对象 Connection connection = JDBCUtils.getConnection(); //(2)存储过程本身也是个sql语句 String sql="call mycall(?)";//存储过程的调用 //(3)获取操作对象(CallableStatement 专用于执行SQL存储过程的接口) CallableStatement call = connection.prepareCall(sql); //(4)接受输出参数前,必须声明对应的占位符(这里没有输入,因此不赋值了) //说明:参数1:占位符的索引,参数2 参数类型 call.registerOutParameter(1,Types.INTEGER); //(5)调用存储过程(sql语句) call.execute(); //(6)获取结果(对应的位置获取对应类型的值) int result = call.getInt(1); System.out.println(result); } }
说明:mysql的存储过程可以带输入(in)和输出参数(out)或(inout),但是对于Java来说似乎没有inout的用法
注意1:包含结果参数的形式(带出参数--out)和一个不包含结果参数的形式
注意2:如果 使用结果参数,则必须将其 声明注册为 out参数;不使用的话就不用声明了六、JDBC调用函数
需求:根据用户名查出对应的密码
package org.wzj.com; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import java.sql.Types; //需求:根据传入的用户名返回对应的密码 public class JDBCTest04 { public static void main(String[] args) throws SQLException { //JDBC调用函数 //(1)倒包后建立数据库的连接对象 Connection connection = JDBCUtils.getConnection(); //(2)存储过程本身也是个sql语句 String sql="{?=call myfunction(?)}";//存储过程的调用 //(3)获取操作对象(CallableStatement 专用于执行SQL存储过程的接口) CallableStatement call = connection.prepareCall(sql); //(4)声明返回值 call.registerOutParameter(1,Types.VARCHAR); //(5)给占位符赋值 call.setString(2,"用户1"); //(6)执行 call.execute(); //(7)获取结果 String result = call.getString(1); System.out.println(result); } }
说明:
七、JDBC中多表的自增长键问题
需求:获取最后插入值的自增长键的值
package org.wzj.com; import java.sql.*; public class JDBCTest05 { public static void main(String[] args) throws SQLException { //需求:获取自增长键的值(自增长的插入的最后一个)--一般用在多表中 Connection connection = JDBCUtils.getConnection(); //(1)预定义SQL语句 String sql="insert into user values(?,?)"; //(2)预编译SQL语句 PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//注意 //(3)插入NULL值--如同mysql中的插入null值,但是Java中不能直接以null的形式直接插入 ps.setNull(1, Types.NULL);//插入NULL值 ps.setString(2,"李四"); ps.executeUpdate(); //(4)向订单表中插入数据(下订单) String insert="insert into orders values(?,?,?)"; PreparedStatement pres = connection.prepareStatement(insert);// pres.setInt(1,1); pres.setInt(2,1500); //(5)获取用户表执行后的"当前"自增长键 ResultSet autokeys = ps.getGeneratedKeys();//获取当前自增长键 int var =0; while(autokeys.next()){ var=autokeys.getInt(1);(此位置是1--批处理是不是获取多个) System.out.println("获取到更新的主键值了"); } pres.setInt(3,var); pres.executeUpdate(); JDBCUtils.close(connection,pres); } }
说明:
八、细节