什么叫做动态代理:就是不用我们手动去编写代理类了,系统会自动帮你生成,生成的类是在内存里,不占用硬盘空间,也不会像静态代理一样添加一个方法就需要改一遍代理类。动态代理就是一劳永逸。
废话不多说直接看代码
首先需要准备一个.properties配置文件
//此文件为配置文件以key-value键值对的方式出现 //加载mysql驱动 jdbc.driver=com.mysql.jdbc.Driver //数据库链接地址 jdbc.connection.url=jdbc:mysql://localhost:3306/lx1 //数据库用户名 jdbc.connection.username=root //数据库密码 jdbc.connection.password=
如图所示的文件:
接下来就开始编写我们的接口类了
package cn.dao; import java.sql.ResultSet; //接口类 public interface JDBC_operation { void getConnection();//获得连接的方法 int executeUpdate(String sql,Object...obj);//增删改 里面需要传入一个sql语句还有一个不定长参数(是为sql语句里面?准备的) ResultSet executeQuery(String sql,Object...obj);//查询 里面需要传入一个sql语句还有一个不定长参数(是为sql语句里面?准备的) void closeAll();//关闭连接资源 }
接下来编写实现类
package cn.dao; import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JDBC_impl implements JDBC_operation{ private static String drivate; private static String url; private static String username; private static String password; private Connection connection; private PreparedStatement preparedStatement; private ResultSet resultSet; //静态代码块获得我们连接数据库所需要的信息 static { Properties properties=new Properties();//这个方法可以读取配置文件.properties InputStream in = JDBC_impl.class.getClassLoader().getResourceAsStream("database.properties"); try { properties.load(in);//load方法可以读取文件 //获得配置文件里面的对应内容 drivate=properties.getProperty("jdbc.driver"); url=properties.getProperty("jdbc.connection.url"); username=properties.getProperty("jdbc.connection.username"); password=properties.getProperty("jdbc.connection.password"); } catch (IOException e) { e.printStackTrace(); } } //连接 @Override public void getConnection(){ try { //加载驱动 Class.forName(drivate); //获得数据库的连接 connection = DriverManager.getConnection(url, username, password); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //增删改 @Override public int executeUpdate(String sql,Object...obj) { try { //用PreparedStatement对象去执行sql代码 preparedStatement = connection.prepareStatement(sql); //不定长参数产生的是一个数组所以我们要用for循环去遍历它的长度(不定长参数可以为空) for (int i=0;i<obj.length;i++){ //给执行的sql语句里面的?赋值 preparedStatement.setObject(i+1,obj[i]); } //执行增删改的方法 int i = preparedStatement.executeUpdate(); //返回行数 return i; } catch (SQLException e) { e.printStackTrace(); //捕获到异常则返回-1 return -1; } } //查询 @Override public ResultSet executeQuery(String sql,Object...obj) { try { //用PreparedStatement对象去执行sql代码 preparedStatement = connection.prepareStatement(sql); //不定长参数产生的是一个数组所以我们要用for循环去遍历它的长度(不定长参数可以为空) for (int i=0;i<obj.length;i++){ //给执行的sql语句里面的?赋值 preparedStatement.setObject(i+1,obj[i]); } //执行查询的方法 resultSet = preparedStatement.executeQuery(); //返回结果集 return resultSet; } catch (SQLException e) { e.printStackTrace(); //捕获到异常则返回-1 return null; } } //关闭 @Override public void closeAll() { if(resultSet!=null){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if(preparedStatement!=null){ try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
好了,接下来就是我们的动态代理了,为什么在这里需要用到动态代理呢是因为JDBC操作的时候总是要连接数据库和释放资源,如果用动态代理就会省略这两步,让系统自动帮我们实现,这样省去了很多的重复操作。
package cn.dao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //创建动态代理需要实现InvocationHandler接口 面向接口实现的动态代理 public class Agent implements InvocationHandler { private JDBC_operation jdbc; public Agent(JDBC_operation jdbc) { this.jdbc = jdbc; } public Agent() { } @Override //第一个参数proxy是真实对象的真实代理对象,invoke方法可以返回调用代理对象方法的返回结果,也可以返回对象的真实代理对象(可以使用反射获取代理对象的信息) //第二个则是需要代理的接口 //第三个则是参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long l = System.currentTimeMillis(); jdbc.getConnection();//代理实现的方法 System.out.println("已连接"); Object o = method.invoke(jdbc, args);//需要传递要代理的接口以及参数 jdbc.closeAll();//代理实现的方法 System.out.println("已关闭"); long l1 = System.currentTimeMillis(); System.out.println("总用毫秒数:"+(l1-l)+"ms"); return o; } }
接下来我们就去测试一下
package cn.dao; import java.lang.reflect.Proxy; import java.sql.ResultSet; import java.sql.SQLException; public class Test { public static void main(String[] args) throws SQLException { JDBC_operation jdbc=new JDBC_impl();//实例化自己定义的方法实现类对象 //第一个参数: 用哪个类加载器去加载代理对象 //第二个参数:动态代理类需要实现的接口 //第三个参数:动态代理方法在执行时,会调用InvocationHandler里面的invoke方法去执行 JDBC_operation o = (JDBC_operation)Proxy.newProxyInstance(jdbc.getClass().getClassLoader(), new Class[]{JDBC_operation.class}, new Agent(jdbc)); String sql="insert into student(stuname) values('哈哈')"; int i = o.executeUpdate(sql); if (i>0){ System.out.println("插入数据成功"); }else { System.out.println("插入数据失败"); } } }
结果如下:
这里需要注意一下,查询的话需要把动态代理的关闭资源方法去掉,需要我们调用之后自己手动关闭,因为不关掉就会出现如下错误:
这个的意思是:线程“main”java中的异常。sql。SQLException:在com处ResultSet关闭后,不允许操作。mysgl。jdbc。SQLError。原因是数据库不允许这样操作,所以我们直接用对象调用关闭的方法就好了
增删改不会出现这种错误
努力到无能为力,拼搏到感动自己