JDBC(二)

本次内容总结使用jdbc访问并操作数据库的流程。

一:获取数据库的连接(四个基本要素 )

要素1:具体数据库厂商的Driver接口实现类,加载与注册JDBC驱动

要素2:数据库URL

要素3:用户名

要素4:密码

代码:获取数据库连接的五种方式,依次迭代优化。

  1 /**
  2  * @author only
  3  */
  4 public class testConnection {
  5 
  6     //连接数据库方式一
  7     @Test
  8     public void test1() throws SQLException {
  9         Driver driver = new com.mysql.jdbc.Driver();
 10         String url = "jdbc:mysql://localhost:3306/bjpowernode";
 11         Properties info = new Properties();
 12         info.setProperty("user","root");
 13         info.setProperty("password","111");
 14 
 15         Connection conn = driver.connect(url,info);
 16         System.out.println(conn);
 17     }
 18 
 19     //连接数据库方式二:对方式一的迭代:在如下的程序中不出现第三方的API,使得程序具有更好的可移植性
 20     @Test
 21     public void test2() throws Exception {
 22         //1.使用反射获取Driver实现类对象
 23         Class clazz = Class.forName("com.mysql.jdbc.Driver");
 24         Driver driver = (Driver) clazz.newInstance();
 25         //2.提供要连接的数据库
 26         String url = "jdbc:mysql://localhost:3306/bjpowernode";
 27         //3.将用户名和密码封装在properties中,使用properties对象提供需要的用户名和密码
 28         Properties info = new Properties();
 29         info.setProperty("user","root");
 30         info.setProperty("password","111");
 31         //4.获取连接
 32         Connection conn = driver.connect(url,info);
 33         System.out.println(conn);
 34     }
 35 
 36     //连接数据库方式三:使用DriverManager替换Driver
 37     @Test
 38     public void test3() throws Exception {
 39         //1.使用反射获取Driver实现类对象
 40         Class clazz = Class.forName("com.mysql.jdbc.Driver");
 41         Driver driver = (Driver) clazz.newInstance();
 42         //2.提供另外三个连接的基本信息:
 43         String url = "jdbc:mysql://localhost:3306/bjpowernode";
 44         String user = "root";
 45         String password = "111";
 46 
 47         //3.注册驱动
 48         DriverManager.registerDriver(driver);
 49         //4.获取连接(也可以传入properties对象)
 50         Connection conn = DriverManager.getConnection(url, user, password);
 51         System.out.println(conn);
 52     }
 53 
 54     //连接数据库方式四:可以仅加载驱动,而不用显示的注册驱动
 55     @Test
 56     public void test4() throws Exception {
 57         //1.提供另外三个连接的基本信息:
 58         String url = "jdbc:mysql://localhost:3306/bjpowernode";
 59         String user = "root";
 60         String password = "111";
 61 
 62         //2.可以仅使用反射加载驱动类,获取Driver实现类对象。无需再注册是因为,Driver的实现类中进行了注册操作。
 63         Class.forName("com.mysql.jdbc.Driver");
 64         //Driver driver = (Driver) clazz.newInstance();
 65         //注册驱动
 66         //DriverManager.registerDriver(driver);
 67 
 68         //3.获取连接(也可以传入properties对象)
 69         Connection conn = DriverManager.getConnection(url, user, password);
 70         System.out.println(conn);
 71     }
 72 
 73 
 74     /**连接数据库方式五(最终版):将数据库连接的4个基本信息(第4个为数据库的驱动类名)声明在配置文件中,通过读取配置文件的方式,获取连接
 75      * 这种方式的好处?
 76      * 1.实现了数据与代码的分离(实现了数据和代码的解耦合)。防止硬编码(代码写死)。当需要更改时仅改配置文件即可。
 77      * 2.如果需要修改配置文件信息,可以避免程序重新打包。
 78      * */
 79     @Test
 80     public void test5() throws Exception {
 81         //1.读取配置文件中的4个基本信息
 82         //类的加载器下的主要方法getResourceAsStream()获取类路径下的指定文件的输入流
 83         InputStream is = testConnection.class.getClassLoader().getResourceAsStream("jdbc.properties");
 84         Properties pros = new Properties();
 85         pros.load(is);
 86         String user = pros.getProperty("user");
 87         String password = pros.getProperty("password");
 88         String url = pros.getProperty("url");
 89         String driverClass = pros.getProperty("driverClass");
 90 
 91         //2.可以仅使用反射加载驱动类,获取Driver实现类对象。无需再注册是因为,Driver的实现类中进行了注册操作。
 92         Class.forName("com.mysql.jdbc.Driver");
 93         //Driver driver = (Driver) clazz.newInstance();
 94         //注册驱动
 95         //DriverManager.registerDriver(driver);
 96 
 97         //3.获取连接(也可以传入properties对象)
 98         Connection conn = DriverManager.getConnection(url, user, password);
 99         System.out.println(conn);
100     }
101 }

获取连接后,就可以通过创建PreparedStatement(预编译sql statement)对象操作数据库。

二:使用PreparedStatement对象实现CRUD操作

(1)操作和访问数据库:

JDBC(二)

 其中PreparedStatement 是 Statement的子接口。但由于Statement有很多弊端(1.需要拼写字符串。 2.存在SQL注入的问题:即指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息 。例如输入的用户名或密码不正确时仍然能查到数据 因此后续就直接使用PreparedStatement接口执行SQL语句,而不用Statement。CallableStatement接口用于执行SQL存储过程。

对于java而言,只要用PreparedStatement取代Statement就可以解决注入问题了!!

JDBC(二)

 

(2)使用PreparedStatement实现通用的 增删改 操作:

 1     //使用PreparedStatement实现通用的增删改操作,将重复步骤封装起来
 2     @Test
 3     public void updateTest() throws Exception {
 4         //删除
 5         String sql = "delete from customers where id = ?";
 6         update(sql,3);
 7 
 8         //改,由于表名‘order’与 sql语句中的关键字order重复,需要加着重符‘‘;
 9         String sql = "update ‘order‘ set name= ?,where id = ?";
10         update(sql,"牛顿",5); //由于sql语句中有两个占位符,所以第二个可变形参args需要传两个参数
11 
12     }
13 
14     //通用的增删改操作,用到可变形参。(可以传任意多个形参)
15     public void update(String sql,Object ...args){ //sql中的占位符个数要与args长度一致,args是一个数组类型
16         Connection conn = null;
17         PreparedStatement ps = null;
18         try {
19             //1.获取数据库连接
20             conn = getConnection();
21             //2.预编译sql语句,返回PreparedStatement实例
22             ps = conn.prepareStatement(sql);
23             //3.填充占位符
24             for (int i=0; i<args.length; i++){
25                 ps.setObject(i+1,args[i]); //注意setObject从 1 开始填充
26             }
27             //4.执行
28             ps.execute();
29         } catch (Exception e) {
30             e.printStackTrace();
31         }
32         //5.资源的关闭
33         closeResource(conn,ps);
34     }
35 
36     //获取数据库连接
37     public Connection getConnection() throws Exception{
38         //1.读取配置文件中的4个基本信息
39         InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
40         Properties pros = new Properties();
41         pros.load(is);
42         String user = pros.getProperty("user");
43         String password = pros.getProperty("password");
44         String url = pros.getProperty("url");
45         String driverClass = pros.getProperty("driverClass");
46 
47         //2.可以仅使用反射加载驱动类,获取Driver实现类对象。无需再注册是因为,Driver的实现类中进行了注册操作。
48         Class.forName("com.mysql.jdbc.Driver");
49 
50         //3.获取连接(也可以传入properties对象)
51         Connection conn = DriverManager.getConnection(url, user, password);
52         return conn;
53     }
54 
55     //关闭连接和Statement操作
56     public void closeResource(Connection conn, PreparedStatement ps){
57         try {
58             if(conn!=null)
59                 conn.close();
60         }catch (Exception e){
61             e.printStackTrace();
62         }
63         try {
64             if(ps!=null)
65                 ps.close();
66         }catch (Exception e){
67             e.printStackTrace();
68         }
69     }

 

(3)使用PreparedStatement实现通用的 操作:(查操作需要返回一个结果集)

 Java与SQL对应数据类型转换表

JDBC(二)

 JDBC(二)

 查询操作的流程示意图 (理解ORM编程思想!以及表字段名和类属性名不同时的处理!)

JDBC(二)

 使用PreparedStatement执行查询操作:

 1     //测试查询操作
 2     @Test
 3     public void queryTest(){
 4         String sql = "select id cid, name cname, email cemail from customer where id < ?";
 5         List<Customer> customer = query(Customer.class, sql, 10);
 6         System.out.println(customer);
 7     }
 8 
 9     //实现通用的查询操作,返回查找到数据的对象
10     @Test
11     public <T> List<T> query(Class<T> clazz, String sql, Object ...args){
12         Connection conn = null;
13         PreparedStatement ps = null;
14         ResultSet rs = null;
15         try {
16             //1.获取数据库连接
17             conn = getConnection();
18             //2.预编译sql语句,返回PreparedStatement实例
19             ps = conn.prepareStatement(sql);
20             //3.填充占位符
21             for (int i=0; i<args.length; i++){
22                 ps.setObject(i+1,args[i]); //注意setObject从 1 开始填充
23             }
24             //4.执行查询(注意这里不是execute了)并得到结果
25             rs = ps.executeQuery();
26             //5.获取结果的元数据,用于得到字段名,和列数
27             ResultSetMetaData rsmd =  rs.getMetaData();
28             int colnum = rsmd.getColumnCount();
29             List<T> ret = new ArrayList<>();
30             while(rs.next()){
31                 T t = clazz.newInstance();
32                 //处理结果集一行数据中的每一列
33                 for(int i=0; i<colnum; i++){
34                     //获取列值
35                     Object colvalue = rs.getObject(i+1);
36                     //获取列名(有别名则获取到别名)
37                     String collabel = rsmd.getColumnLabel(i+1);
38                     //通过反射,给t对象的coluname属性赋值为colvalue
39                     Field field = clazz.getDeclaredField(collabel);
40                     field.setAccessible(true);
41                     field.set(t,colvalue);
42                 }
43                 ret.add(t);
44             }
45             return ret;
46         } catch (Exception e) {
47             e.printStackTrace();
48         } finally {
49             //5.资源的关闭
50             closeResource(conn, ps, rs);
51         }
52         return null;
53     }

JDBC(二)

 

 

参考 :https://www.bilibili.com/video/BV1eJ411c7rf?

JDBC(二)

上一篇:Mysql之读写分离架构-Atlas


下一篇:es和数据库的对应关系