Java学习日志Day31_ResultSet_jdbc查询员工表_Statement执行DDL,DML语句的弊端_PreparedStatement_数据库连接池(初窥)

一、ResultSet :结果集的数据表

Java学习日志Day31_ResultSet_jdbc查询员工表_Statement执行DDL,DML语句的弊端_PreparedStatement_数据库连接池(初窥)

举例1:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcTest {
    public static void main(String[] args)  {
        Connection conn = null ;
        Statement stmt = null ;
        try {
            //获取数据库连接
            conn = JdbcUtils.getConnection();
            //准备sql
            String sql = "update student set address = '北京市' where id = 13" ;
            //获取Statement对象
            stmt = conn.createStatement();
            //准备执行
            int count = stmt.executeUpdate(sql);
            System.out.println("更新成功");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(stmt,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    //声明成员属性
    private static String driver = null ;
    private static String url = null ;
    private static String user = null ;
    private static String password = null ;
    //    提供一个静态代码块
    static{
        try {
            //创建一个属性集合类对象
            Properties prop = new Properties() ;
            //读取配置文件
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            prop.load(inputStream);
            //通过key获取value
            driver = prop.getProperty("driver");
            url = prop.getProperty("url") ;
            user = prop.getProperty("user") ;
            password = prop.getProperty("password") ;
            //注册驱动
            Class.forName(driver) ;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private JdbcUtils(){}
    //获取数据连接对象的方式
    public static Connection getConnection(){
        Connection conn = null ;
        try {
            conn = DriverManager.getConnection(url,user,password) ;
            return conn ;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null ;
    }
    //提供关闭资源方法:针对DQL语句:查询获取结果集,关闭相关资源
    public static void close(ResultSet rs, Statement stmt,Connection conn) throws SQLException {
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            conn.close();
        }
    }

    //针对DDL,DML操作:不需要ResultSet
    public static void close(Statement stmt,Connection conn) throws SQLException {
        close(null,stmt,conn);
    }
    public static void main(String[] args) {
        Connection connection = JdbcUtils.getConnection();
        System.out.println(connection);
    }
}
举例2:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcTest2 {
    public static void main(String[] args) {
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;

        try {
            //获取数据库的链接对象
            conn = JdbcUtils.getConnection();
            //获取执行对象
            stmt = conn.createStatement();
            //准备sql
            String sql = "select * from emp" ;

            //执行查询
            //public ResultSet executeQuery(String sql)
            rs  = stmt.executeQuery(sql);

            //boolean next():判断结果集数据表中是否存在有效数据,true,就向前移动一行
            //防止如果没有数据了,不能在移动了,否则就异常了,加入判断
         /*   //第一次
            if(rs.next()){ //true
                //获取
                //XXX getXXX(int columnIndex):列的索引获取:第一列就是1
                //XXX getXXX(String columnName) 列的名称获取
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t"+name+"\t"+address);
            }

            //第二次
            if(rs.next()){ //true
                //获取
                //XXX getXXX(int columnIndex):列的索引获取:第一列就是1
                //XXX getXXX(String columnName) 列的名称获取
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t"+name+"\t"+address);
            }

            //第三次
            if(rs.next()){ //true
                //获取
                //XXX getXXX(int columnIndex):列的索引获取:第一列就是1
                //XXX getXXX(String columnName) 列的名称获取
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t"+name+"\t"+address);
            }

            //第四次
            if(rs.next()){ //true
                //获取
                //XXX getXXX(int columnIndex):列的索引获取:第一列就是1
                //XXX getXXX(String columnName) 列的名称获取
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t"+name+"\t"+address);
            }*/

         //改进:代码重复很高,循环:while循环
            while(rs.next()){
                //获取
                //XXX getXXX(int columnIndex):列的索引获取:第一列就是1
                //XXX getXXX(String columnName) 列的名称获取
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t"+name+"\t"+address);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(rs,stmt,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

二、需求:要通过jdbc查询员工表(ResultSet的使用)

/* 需求:
 *  现在将emp表中的每一条记录封装到实体类中:Emp (员工类),将整个的员工的所有数据最终
 *  存储在List<Emp>,将员工的信息遍历出来!
 *
 *  1)需要有一个员工类Emp它需要和员工表的emp的字段一一对应
 *              id 属性
 *              name属性
 *              address属性
 *
 *  2)定义一个接口:
 *          EmpDao
 *          查询所有的员工信息
 *          public List<Emp>  findAllEmp() ;
 *
 *  3)定义一个接口的实现类
 *          EmpDaoImpl
 *          public List<Emp>  findAllEmp() {
 *              //创建空的集合
 *              //jdbc操作----查询所有员工表数据
 *          }
 *     4)在测试类中:可以通过接口多态的方式进行测试,完成数据查询!
 */
import com.qf.dao.EmpDao;
import com.qf.dao.impl.EmpDaoImpl;
import com.qf.entity.Emp;
import java.util.List;

public class JdbcTest3 {
    public static void main(String[] args) {

        //查询所有员工信息
        EmpDao ed = new EmpDaoImpl() ;
        List<Emp> empList = ed.findAllEmp();
        for(Emp emp :empList){
           // System.out.println(emp);
            System.out.println(emp.getId()+"\t"+emp.getName()+"\t"+emp.getAddress());
        }
    }
}
 /*  属性和emp表中字段对应
 *  提供公共访问方法
 */
public class Emp {
    private Integer id ; //员工编号
    private String name ;//员工姓名
    private String address ; //员工的住址

    public Emp() {
    }

    public Emp(Integer id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}


import com.qf.entity.Emp;
import java.util.List;

/* 针对员工数据库访问接口层
 */
public interface EmpDao {

    //查询所有
    public List<Emp> findAllEmp() ;

    //查询单个员工信息
    public Emp findEmpById(Integer id) ;

    //添加员工信息
    public void addEmp(Emp emp) ;

    //删除员工信息:通过id删除

    //修改员工信息

    //查询总记录数
    public int getTotalCount() ;
}

import com.qf.dao.EmpDao;
import com.qf.entity.Emp;
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author:zhangyang
 * @Date: 11:05
 * @Version 1.0
 * 针对员工的数据访问接口实现层
 */
public class EmpDaoImpl implements EmpDao {

    @Override
    public List<Emp> findAllEmp() {
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;

        try {
            //创建一个集合对象
            List<Emp> list = new ArrayList<Emp>() ;
            //创建数据库的连接对象
            conn = JdbcUtils.getConnection();
            //获取执行对象
            stmt = conn.createStatement() ;
            //sql语句
            String sql = "select * from emp" ;
            //查询
            rs = stmt.executeQuery(sql);

            //声明变量emp:类型Emp
            Emp emp = null ;
            //遍历结果集
            while(rs.next()){
                //通过列的名称来获取
                //创建员工对象
                emp = new Emp() ;
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                String address = rs.getString("address") ;
                //封装员工数据
                emp.setId(id);
                emp.setName(name);
                emp.setAddress(address);

                //将员工添加集合中
                list.add(emp) ;
            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(rs,stmt,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null ;
    }

    /**
     * 根据员工编号查询员工信息
     * @param id  员工编号
     * @return 返回的当前员工
     */
    @Override
    public Emp findEmpById(Integer id) {
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;
        try{
            //获取连接
            conn = JdbcUtils.getConnection();
            stmt =  conn.createStatement() ;
            String sql = "select * from emp where id =5" ;
            rs =  stmt.executeQuery(sql) ;
            Emp emp = null ;
            while(rs.next()){
                emp = new Emp() ;
                int empId = rs.getInt(1) ;
                String empName = rs.getString(2) ;
                String empAddress = rs.getString(3) ;
                emp.setId(empId);
                emp.setName(empName);
                emp.setAddress(empAddress);
            }
            return emp ;
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(rs,stmt,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public int getTotalCount() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //获取连接
            conn = JdbcUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select count(id) from emp";
            ResultSet resultSet = stmt.executeQuery(sql);
            int count = 0;
            while (rs.next()) {
                count = rs.getInt("id");
                System.out.println(count);
            }


        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                JdbcUtils.close(rs, stmt, conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    return 0 ;
    }

    /**
     * 添加员工信息
     * @param emp  具体的员工对象
     */
    @Override
    public void addEmp(Emp emp) {
    }
}
/*测试类*/
import com.qf.dao.EmpDao;
import com.qf.dao.impl.EmpDaoImpl;
import com.qf.entity.Emp;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;

/* Junit包使用@Test注解:执行单元测试注解
 * @Before:在执行@Test标记的单元测试方法之前,先执行
 *      一些业务相关的初始化操作
 *
 * @After:在执行@Test标记的单元测试方法之后执行:
 *     一般释放资源都可以放在这里面
 */
public class JdbcTest {

   /* @Before
    public void init(){
        //初始化操作
        System.out.println("初始化操作完成...");
    }*/

    @Test
    //测试查询所有
    public void testFindAll(){

        //测试EmpDao中的接口 findAllEmp()
        EmpDao empDao = new EmpDaoImpl() ;
        List<Emp> list = empDao.findAllEmp();
        for(Emp emp:list){
            System.out.println(emp);
        }
    }

    //测试根据id查询某个员工
    @Test
    public void testFindEmpById(){
        EmpDao empDao = new EmpDaoImpl() ;
        Emp emp = empDao.findEmpById(5);
        System.out.println(emp);
    }

    /*@After //在执行单元测试方法之后执行
    public void myclose(){
        System.out.println("资源被关闭");
    }*/
}

三、Statement对象执行DDL,DML语句的弊端

  1. 使用Statement模拟登录操作
    键盘录入用户名和密码,和数据库中存储的用户名和密码进行对比!
    如果一致,提示登录成功,否则失败

  2. SQL注入:
    使用Statement执行静态sql语句:存在字符串拼接 (存在安全问题!)
    SELECT * FROM USER WHERE username = ‘sdfsfs’ AND PASSWORD = ‘a’ OR ‘a’ = ‘a’ ;
    针对sql的执行效率低
    Statement对象.executeUpdate(String sql)/executeQuery(String sql)

  3. PreparedStatement书写sql—可以有效防止sql注入(推荐)
    而且提高的sql的执行效率

  4. 先将参数化的sql发送数据库:进行预编译完成(通过类型校验)将sql存储在PreparedStatement内存中
    SELECT * FROM USER WHERE username = ? AND PASSWORD = ? ;

  5. 直接通过?占位符号给当前进行实际参数赋值!
    PreparedStatement.executeUpdate() / executeQuery()

举例:
import com.qf.utils.JdbcUtils;
import java.sql.*;
import java.util.Scanner;

public class StatemetDemo {
    public static void main(String[] args) {
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        //提示并录入
        System.out.println("请您输入用户名:");
        String username = sc.nextLine() ;

        System.out.println("请您输入密码:");
        String password = sc.nextLine() ;

        //调用登录的功能
        boolean flag = isLogin2(username,password) ;
        if(flag){
            System.out.println("登录成功...");
        }else{
            System.out.println("对不起,用户名或者密码错误!");
        }
    }

    //使用PreparedStatement对象来完成登录操作
    private static boolean isLogin2(String username, String password) {

        Connection connection = null ;
        PreparedStatement ps = null ;
        ResultSet rs = null ;
        try {
            connection  = JdbcUtils.getConnection();
            String sql = "select * from user where username = ? and password = ?" ;
            System.out.println(sql);
            ps =  connection.prepareStatement(sql) ;//已经参数化的发送数据库进行编译

            //参数赋值
            ps.setString(1,username);
            ps.setString(2,password);

            //执行查询
            rs = ps.executeQuery();
            return rs.next() ;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(rs,ps,connection);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return false ;
    }

    //登录的功能
    //使用statement来操作数据库
    private static boolean isLogin(String username, String password) {

           Connection conn = null ;
           Statement stmt = null ;
           ResultSet rs  = null ;
        try {
            //创建数据库连接对象
            conn = JdbcUtils.getConnection();
            //通过连接对象获取执行对象
            stmt = conn.createStatement();
            //准备sql语句
            //字符串拼接
            String sql =
                    "select * from user where username = '"+username+"' and password = '"+password+"'" ;
            System.out.println(sql);
            //准备执行
            rs = stmt.executeQuery(sql);
            return rs.next() ;//如果当前返回true,光标向前移动,就通过用户名和密码查询到!
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }
}

四、PreparedStatement:预编译对象的使用(推荐使用预编译sql)

  1. 步骤:
    1)加载驱动
    2)获取数据库连接对象
    3)准备好参数的sql语句 :带条件的查询 /增删改,都带上? 占位符号
    4)获取的预编译对象:将参数化的sql存储在编译对象中
    5)给参数进行赋值
    6)查询/更新操作
    7)释放资源
举例:
import com.qf.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PreparedStatementTest {
    public static void main(String[] args)  {

        Connection conn = null ;
        PreparedStatement ps = null ;
        try {
            //获取数据库的链接对象
             conn = JdbcUtils.getConnection();

            //准备好参数化的sql
            String sql = "insert into emp values(?,?,?) " ;
            //通过链接对象获取预编译对象并将sql进行 参数编译(编译当前类型等等)
            //PreparedStatement prepareStatement(String sql) throws SQLException
             ps = conn.prepareStatement(sql);
            //准备参数赋值
            //void setXXX(int parameterIndex,int x)
            //参数1:第几个占位符号的索引值(1开始)
            //参数2;当前给参数1赋的实际参数
            ps.setInt(1,7);
            ps.setString(2,"李渊") ;
            ps.setString(3,"南窑国际") ;

            //执行更新的通用操作;int executeUpdate()
            //执行查询的通用澳洲:ResultSet executeQuery()
            int count = ps.executeUpdate();
            System.out.println(count);
            System.out.println("更新成功");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.close(ps,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

五、数据库连接池(池化技术)

  1. 手动封装工具:JdbcUtils:存在问题
    对于增删查改,都需要获取连接对象(Connection:需要被频繁的创建-----销毁资源过多)

  2. 连接池:
    可以管理很多个连接对象,里面有一些参数配置,最大连接数量,最大激活数量,最小数量
    空闲数量,最大等待时间,都可以对连接池进行优化,连接对象使用完毕,不会从内存被释放而是继续归还到
    连接池中:

  3. java.sql.DataSource:物理数据源的链接:替代DrvierManager
    举例:
    dbcp
    c3p0:早期的连接池
    druid: 德鲁伊连接池(推荐)
    最大连接数:10
    当前创建第 11个对象:— jvm输出错误日志,可将某个Connection使用完毕close()
    归还到连接池中,第11个连接对象就可以使用!

  4. 对于c3p0的使用:
    1)两个jar包
    核心包:c3p0-0.9.1.2.jar
    依赖包:mchange-commons-java-0.2.12.jar

举例1:
public class C3p0Demo {

    public static void main(String[] args) throws SQLException {
        //创建c3p0的连接池对象
        ComboPooledDataSource pooledDataSource = new ComboPooledDataSource() ;
        //那么就自动读取c3p0-config.xml文件的defalut-config的配置
        //如果执行的有参构造方式:读取配置文件中named-config
        //Connection getConnection() throws SQLException;重写了DataSource接口的获取连接的方法
        for(int x = 1 ; x<=11;x ++){

            Connection connection =
                    pooledDataSource.getConnection();
            if(x == 5){
                connection.close(); //而是第二个连接对象 归还到连接池中
            }
            System.out.println(connection);
        }
    }
}
举例2:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.ConnectionEvent;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/* 加入DruidDataSource(类 实现java.sql.DataSource:物理数据源的链接))以及ThreadLocal :线程(并发)
 */
public class MyJdbcUtils {
    private static DataSource dataSource = null ;
    private static ThreadLocal<Connection>  t1 = new ThreadLocal<Connection>() ;
    //一个链接对象---相当线程

    private MyJdbcUtils(){}
    static{
        try {
            //创建一个属性集合类
            Properties prop = new Properties() ;

            //读取druid.properties的参数
            InputStream inputStream = MyJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            //加载属性集合列表中
            prop.load(inputStream);

            //通过工厂类
             dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据链接
    public static Connection getCoonnection(){
        //声明conn变量
        Connection conn = null ;

        try{
            //获取连接对象
            //先判断 ,如果当前conn 为null
            if(conn==null){
                //从连接池获取到
                conn  = dataSource.getConnection();

                //一个连接相当一一个线程
                //连接对象绑定ThreadLocal中
                t1.set(conn);
            }
            return conn ;
        }catch(Exception e){
            e.printStackTrace();
        }
           return null ;
    }
    //获取数据源
    public static DataSource getDataSource(){
        return dataSource;
    }

    //释放资源
    //提供关闭资源方法:针对DQL语句:查询获取结果集,关闭相关资源
    public static void close(ResultSet rs, Statement stmt, Connection conn) throws SQLException {
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            conn.close();

            //解绑:从ThreadLocal (连接使用完毕,线程就执行完毕
            t1.remove();
        }
    }

    //针对DDL,DML操作:不需要ResultSet
    public static void close(Statement stmt,Connection conn) throws SQLException {
        close(null,stmt,conn);
    }

    //开启事务
    public static void setAutoCommit(){
        Connection conn = null ;
        try {
            conn  = getCoonnection();
            //        //开启事务
            conn.setAutoCommit(false); //取消自动提交
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //如果事务的操作没有问题,提交事务并释放连接
    public static void commitAndClose() throws SQLException {

            Connection conn  =    getCoonnection();
            //提交事务
             conn.commit();
             //释放连接
             conn.close();
             //解绑
             t1.remove(); //线程(用户操作的时候,连接对象是完毕,线程执行完毕!)
    }

    //如果执行过程中出现问题,回滚事务
    public static void rollbackAndClose() throws SQLException {
        Connection conn  =    getCoonnection();
        //事务回滚
        conn.rollback();
        //释放连接--归还到连接池
        conn.close();
        //解绑
        t1.remove(); //线程(用户操作的时候,连接对象是完毕,线程执行完毕!)
    }

    public static void main(String[] args) {
        Connection connection = MyJdbcUtils.getCoonnection();
        System.out.println(connection);

        DataSource dataSource = MyJdbcUtils.getDataSource();
        System.out.println(dataSource);
    }
}

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/* Druid:德鲁伊连接池
 *  阿里提供的开源的!
 * 
 *  基本使用步骤:
 *  1)导入核心包:druid-1.0.9.jar
 *  2)src防止druid.properties配置文件
 *  3)创建DruidDataSrource---->工厂类DruidDataSourceFactory调用createDruidDataSource方法完成创建!
 *  4)获取数据库连接对象
 */
public class DruidDataSourceDemo {
    public static void main(String[] args) throws Exception {
        //创建一个属性集合类
        Properties prop =new Properties() ;
        InputStream inputStream = DruidDataSourceDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        prop.load(inputStream);
        System.out.println(prop);
        //  public static DataSource createDataSource(Properties properties)
         DataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
        System.out.println(dataSource);
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
}
上一篇:数据仓库工具 hive的入门(七)HQL操作之--DML命令


下一篇:通过binlog统计DML操作的次数