MySql - 基础学习8 - mysql拓展

一.SQL注入的问题

sql存在漏洞,会被攻击和数据泄露(statement对象)

SQL语句会被自动拼接  如果输入字符有 OR 那可以保证后面数据永远为真,例如:‘ ’(空字符)or ‘ 1 = 1 ’

以上这样的语句会导致sql语句拼接时候出错后面永远为真,所以前面输入什么都没关系,整体都为真

二.preparedStatement对象(防sql注入)

使用PreparedStatement对象来执行java所编写的sql语句可以防止sql注入的问题,比本来的Statement对象的执行更加安全

使用PreparedStatement对象插入

    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st =null;
        ResultSet rs=null;
        try {
            conn=JdbcUtils.getConnection();
            String sql="insert into `users`(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";//不放入值,用?占位
            st=conn.prepareStatement(sql);//sql 预编译
            st.setInt(1,4);
            st.setString(2,"maming");
            st.setString(3,"112233");
            st.setString(4,"asdf@1234");
            // 这里的最外面new 的对象是要插入的sql格式的时间,而里面new的Date()是java对象所含的现在时间
            st.setDate(5,new java.sql.Date(new Date().getTime()));
            int i=st.executeUpdate();
            if(i>0){
                System.out.println("PreparedStatement对象插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }

 

使用PreparedStatement对象查找

public class TestSelectPro {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st=null;
        ResultSet rs=null;
        try {
            conn=JdbcUtils.getConnection();
            String sql ="select * from `users` where id=?";
            st = conn.prepareStatement(sql);
            st.setInt(1,2);
            rs= st.executeQuery();
            while(rs.next()){
                System.out.println("name="+rs.getString("NAME"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

 

区别:

  • PreparedStatement对象使用了  ? 作为占位符
  • 需要预编译sql,先写sql语句和拿到PreparedStatement对象,不执行
  • 手动给参数赋值,(第几个问号,赋什么值)
  • 执行

本质:PreparedStatement对象放注入的本质就是把传进来的参数当作了字符,里面的 ‘ 就会被直接转义,就不会发生那种从客户端输入一句sql的情况了

Java实现事务:

ACID原则:

原子性:要么完成,要么都不完成

一致性:总数不变

持久性:一旦提交不可逆,持久化到数据库

隔离性:多个进程互不干扰

隔离性产生的问题:

脏读:一个事务读取了另一个欸有提交的事务

不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变

虚读(幻读):在一个事务内,读取到了别人插入的数据

public class TestTrunsation {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        ResultSet rs=null;
        try {
            conn=JdbcUtils.getConnection();
            conn.setAutoCommit(false);// 关闭自动提交,Java默认开启事务
            String sql1 ="update account set money= money -100 where name = 'A'";
            st=conn.prepareStatement(sql1);
            st.executeUpdate();
            String sql2 ="update account set money= money +100 where name = 'B'";
            st=conn.prepareStatement(sql2);
            st.executeUpdate();
            // 业务成功,提交
            conn.commit();
            System.out.println("成功!");
        } catch (SQLException e) {
            try {
                // 失败就回滚
                conn.rollback();
                System.out.println("失败!");
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

 

代码实现:

  • 开启事务:conn.setAutocommit()
  • 一组业务执行完毕,提交事务
  • 可以在catch中显示增加回滚,java默认也会事务回滚

三.数据库连接池

数据库连接   -----  执行完毕  ----释放

直接连接了,然后用一次立马释放太浪费资源了,所以衍生出了池化技术

池化技术:准备一些预先资源,过来连接预先准备好的

关键词:

最小连接数:10

最大连接数:15(数字根据具体来)

等待超时:100ms

编写连接池,实现一个接口:DataSource

开放数据源实现:DBCP,C3P0,Druid(阿里巴巴)

DBCP:导包(我选择maven)

  <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.1.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
      <version>2.4.2</version>
    </dependency>

 

数据源:dbcpconfig.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED​

 

DBCP工具类:

public class JdbcUtils_DBCP {
    private static DataSource dataSource=null;
    static {
        try{
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(in);
            // 创建数据源  工厂模式    --》创建对象
            dataSource=BasicDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获取链接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();  // 从数据源中获取连接
    }
    //释放链接
    public static void release(Connection conn, Statement st, ResultSet re){
        if(re!=null){
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

 

测试DBCP

public class TestDBCP {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st =null;
        ResultSet rs=null;
        try {
            conn= JdbcUtils_DBCP.getConnection();
            String sql="insert into `users`(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";//不放入值,用?占位
            st=conn.prepareStatement(sql);//sql 预编译
            st.setInt(1,7);
            st.setString(2,"maming");
            st.setString(3,"112444");
            st.setString(4,"asdf@1234");
            // 这里的最外面new 的对象是要插入的sql格式的时间,而里面new的Date()是java对象所含的现在时间
            st.setDate(5,new java.sql.Date(new Date().getTime()));
            int i=st.executeUpdate();
            if(i>0){
                System.out.println("PreparedStatement对象插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils_DBCP.release(conn,st,rs);
        }
    }
}

 完结撒花!

posted @ 2022-11-11 22:16  回忆也交给时间  阅读(28)  评论(0编辑  收藏  举报