JDBC核心技术-day1

JDBC概述:
JDBC核心技术-day1_第1张图片
JDBC(java database connectivity):
是一个独立于特定数据库管理系统,通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准JAVA类库,使用这些类库可以以一种标准的方法,方便地访问数据库资源。

数据的持久化:把数据保存到可掉电式存储设备中以供以后使用,大多数情况下,特别是企业级应用,数据持久化意味着内存中的数据保存到硬盘上加以"固化",而持久化的实例过程大多通过各种关系数据库来完成。

持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件,XML数据文件中

JDBC是java访问数据库的基石,JDO、Hibernate、MyBatis等只是更好的封装了JDBC

获取数据库连接:
方式1:使用Driver接口

public class ConnectionTest {
    public void testConnection1() throws SQLException {
        Driver driver = new com.mysql.jdbc.Driver();
        String url = null;
        Properties info = null;

        Connection conn = driver.connect(url,info);

        System.out.println(conn);
    }
}

方式2:对方式1的迭代(在如下的程序中不出现第三方的API,使得程序具有更好的可移植性)

  public void testConnection1() throws Exception {
        //获取Driver实现类的对象,使用反射
       Class clazz = Class.forName("com.mysql.jdbc.Driver");
       Driver driver = (Driver)clazz.newInstance();

       //提供要连接的数据库
       String url = "jdbc:mysql://localhost:3306/test";

       //提供连接需要的用户名和密码
       Properties info = new Properties();
       info.setProperty("user","root");
       info.setProperty("password","");

       //获取连接
        Connection conn = driver.connect(url,info);
        System.out.println(conn);
        
    }

方式3:使用DriverManger替换Driver

public void testConnection1() throws Exception {
        //获取Driver实现类的对象
        Class clazz = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) clazz.newInstance();

        //提供另外三个连接的基本信息
        String url = "jdbc:mysql://localhost:3306/test";
        String user = "root";
        String password = "";

        //注册驱动
        DriverManager.registerDriver(driver);

        //获取连接
        Connection conn = DriverManager.getConnection(url,user,password);
        
        System.out.println(conn);

    }

方式4 可以只是加载驱动,不用显式的注册驱动了

 public void testConnection1() throws Exception {


        //提供另外三个连接的基本信息
        String url = "jdbc:mysql://localhost:3306/test";
        String user = "root";
        String password = "";
        
        //加载Driver
        Class.forName("com.mysql.jdbc.Driver");
        

        //获取连接
        Connection conn = DriverManager.getConnection(url,user,password);

        System.out.println(conn);

    }

方式5(final版):将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接.

好处:
1.实现了数据与代码分离,实现了解耦
2.如果需要修改配置文件信息,可以避免程序重新打包。

新建一个jdbc.properties文件,输入
JDBC核心技术-day1_第2张图片

   public void testConnection1() throws Exception {
        //读取配置文件中的4个基本信息
        InputStream is = test4.class.getClassLoader().getResourceAsStream("jdbc.properties");

        Properties pros = new Properties();
        pros.load(is);

        String user = pros.getProperty("users");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //加载驱动

        Class.forName(driverClass);

        //获取连接
        Connection conn = DriverManager.getConnection(url,user,password);
        System.out.println(conn);

     }

使用Statement接口执行SQL语句:
存在拼串操作繁琐,SQL注入问题
SQL注入问题:是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据注入非法的SQL语句段或命令(如:SELECT USER,PASSWORD FROM USER_TABLE WHERE USER=‘A OR 1 =’ AND PASSWORD = 'OR ‘1’ = ‘1’ ),从而利用系统的SQL引擎完成恶意行为的做法。

避免SQL注入:使用PreparedStatement(从Statement扩展而来)取代Statement

在数据库中插入数据

   public void testInsert() {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);

            String user = pros.getProperty("users");
            String password = pros.getProperty("password");
            String url = pros.getProperty("url");
            String driverClass = pros.getProperty("driverClass");

            Class.forName(driverClass);

            conn = DriverManager.getConnection(url,user,password);
//            System.out.println(conn);

            String sql = "insert into customers(name,email,birth)values(?,?,?)";//?是占位符
            ps = conn.prepareStatement(sql);
            ps.setString(1,"哪吒");
            ps.setString(2,"[email protected]");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            java.util.Date date = sdf.parse("1000-01-01");
            ps.setDate(3,new Date(date.getTime()));

            //执行操作
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //资源的关闭
         finally {

            try {
                if (ps != null)
                    ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

通用的增删改操作:

 public void update(String sql,Object ...args) {//sql中的占位符的个数与可变形参的长度相同
        Connection conn = null;
        PreparedStatement ps = null;
        //通用的增删改操作
        try {
            //获取数据库的连接
            conn = JDBCUtil.getConnection();
            //预编译SQL语句,返回PreparedStatement的实例
            ps = conn.prepareStatement(sql);
            //填充占位符
            for (int i = 0;i < args.length;i++){
                ps.setObject(i+1,args[i]);//小心参数声明错误!
            }
            //执行
            ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            //资源的关闭
            JDBCUtil.closeResource(conn,ps);
        }
    }

JDBC核心技术-day1_第3张图片

针对customer表的通用的查询操作

  @Test
    public void testQueryForCustomers(){
        String sql = "select id,name,birth,email from customers where id = ?";
        Customer customer = queryForCustomers(sql,13);
        System.out.println(customer);
    }


    public Customer queryForCustomers(String sql,Object...args){

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);

            for (int i = 0;i<args.length;i++){
                ps.setObject(i+1,args[i]);

            }
            rs = ps.executeQuery();
            //获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //通过ResultSetMetaData获取结果集的列
            int columnCount = rsmd.getColumnCount();
            if (rs.next()){
                Customer cust = new Customer();
                //处理结果集一行数据中的每一个列
                for (int i=0;i<columnCount;i++){
                    //获取列值
                    Object columnvalue = rs.getObject(i+1);

                    //获取每个列的列名
                    String columnName = rsmd.getColumnName(i+1);

                    //给cust对象指定的columnName属性,赋值为columnvalue
                    Field field = Customer.class.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(cust,columnvalue);

                }
                return cust;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.closeResource(conn,ps,rs);
        }
         return null;
    }

遇到Method xxx should be void 错误,是因为@test不能用于有返回值的方法,去掉@test

ORM编程思想(Object relational mapping):
一个数据表对于一个java类
表中的一条记录对应Java类的一个对象
表中的一个字段对应java的一个属性

JDBC核心技术-day1_第4张图片
针对不同表的通用查询操作:

方式1:

  @Test
    public void testGetInstance(){
        String sql = "select id,name,email from customers where id = ?";
        Customer customer = getInstance(Customer.class,sql,12);
        System.out.println(customer);

        String sql1 = "select order_id orderId,order_name orderName from `order` where order_id =?";
        Order order = getInstance(Order.class,sql1,1);
        System.out.println(order);
    }
    public <T> T getInstance(Class<T> clazz,String sql,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtil.getConnection();

            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();

            if (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    //获取每个列的列值:通过ResultSet
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名: getColumnName()
                    //获取每个列的别名:getColumnLabel()
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    //
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.closeResource(conn, ps, rs);
        }

        return null;
    }

方式2:

  @Test
    public void testGetForList(){
        String sql = "select id,name,email from customers where id < ?";
        List<Customer> list = getForList(Customer.class,sql,12);
        list.forEach(System.out::println);
    }

    public <T> ArrayList<T> getForList(Class<T> clazz, String sql, Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtil.getConnection();

            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            //创建集合对象
            ArrayList<T> list = new ArrayList<T>();
            while (rs.next()) {
                T t = clazz.newInstance();
                //处理结果集一行数据中的每一个列:给t对象指定的属性赋值
                for (int i = 0; i < columnCount; i++) {
                    //获取每个列的列值:通过ResultSet
                    Object columnValue = rs.getObject(i + 1);
                    //获取每个列的列名: getColumnName()
                    //获取每个列的别名:getColumnLabel()
                    String columnLabel = rsmd.getColumnLabel(i + 1);
                    //
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columnValue);
                }
                list.add(t);

            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtil.closeResource(conn, ps, rs);
        }

        return null;
    }

除了解决Statement的拼串、SQL问题之外,PreparedStatement还有哪些好处?
1.PreparedStatement操作Blob的数据,而Statement做不到
2.PreparedStatement可以实现更高效的批量操作

你可能感兴趣的:(java,java,jdbc)