目录
SQL注入问题及解决方案
SQL注入问题
SQL注入问题解决方案
连接池
连接池的工作原理
连接池的作用
连接池的优势
连接池的使用
以c3p0为例讲解连接池的使用
SQL注入问题:利用非法的SQL拼接来达到入侵数据库的目的
示例:
登录查询操作
public class UserDao { boolean doLogin(String name ,String password) { try { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/java_test", "root", "******"); System.out.println("连接成功"); Statement statement = connection.createStatement(); //正确的查询语句 String sql = "select * from user where name = '"+name+"' and password = '"+password+"'"; ResultSet resultSet = statement.executeQuery(sql); if(resultSet.next()) return true; // 关闭资源 resultSet.close(); statement.close(); connection.close(); } catch (Exception e) { System.out.println("连接失败"); e.printStackTrace(); } return false; }
传入正确的参数,则返回true,查询成功;
public static void main(String[] args) { UserDao userDao = new UserDao(); boolean lisi = userDao.doLogin("lisi", "200"); System.out.println(lisi); }
若参数错误,如密码错误
boolean lisi = userDao.doLogin("lisi", "2000");
若插入错误的SQL语句,即使参数传入错误也能查询成功
String sql = "select * from user where name = '"+name+"' and password = '"+password+"'"; UserDao userDao = new UserDao(); boolean lisi = userDao.doLogin("lisi ’#", "2000");
这就是SQL注入问题了
在上述代码中,是使用用户名和密码来和SQL进行拼接查询数据库,查询操作是需要用户名和密码正确才能执行成功。
本应该通过sql的非法拼接改变SQL语句的语义,就达到了入侵数据库的目的 。
当参数变成 “ lisi ’# ” 时,“‘#”会将后面的内容注释掉,就不在判断passwd是否正确,因此对应登录操作给定用户名,不知道密码情况下也能完成登陆
使用preparedStatement代替Statement
String sql = "select * from user where name = ? and password = ?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1,name); preparedStatement.setString(2,password); ResultSet resultSet = preparedStatement.executeQuery(); if(resultSet.next()) return true; boolean lisi = userDao.doLogin("lisi'# ", "2000");
在创建preparedStatement对象时,就将sql语句传入,进行预编译,prepared Statement采用预编译处理机制,SQL和参数分别传递,SQL上参数的位置通过占位符'?'处理;preparedStatement . setString起始位置为1 ,当传入参数时,特殊值就不会被起作用了。
数据库连接池的基本思想:为数据建立一个连接池,预先在池中放入一定数量的连接,当有数据库操作时,在池中获取一个空闲的连接来支持数据库的操作,当当前的数据库操作完成后,将连接放回池中。
在JDBC请求MySQL数据库的操作都要进行连接、释放的过程,在并发量大的情况下,频繁的连接和释放势必会消耗系统的性能。可以使用连接复用的方式让来连接重复使用。
1.资源复用
2.更快的响应速度
3.新的资源分配手段
4.统一的连接关系,避免数据库连接泄露
1.导入连接
2.参数配置
3.通过连接池获取连接
4.进行SQL操作
1.引入c3p0连接
<!--c3p0连接池--> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>
2.给定c3p0的配置文件 :c3p0-config.xml (名字不能修改)
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!--配置连接池mysql--> <named-config name="mysql"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/ssms</property> <property name="user">root</property> <property name="password">123456</property> <!-- 初始化连接数 --> <property name="initialPoolSize">10</property> <!--最大空闲时间,多少秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime">30</property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize">100</property> <!-- 最小连接数 --> <property name="minPoolSize">10</property> </named-config> </c3p0-config>
3.连接池编码
//设置数据源DataSource ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql"); try { //获取Connection Connection connection = dataSource.getConnection(); //获取Statement对象 Statement statement = connection.createStatement(); String sql = "select * from user where id = 25"; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) { Integer id1 = resultSet.getInt("id"); String account = resultSet.getString("account"); String name = resultSet.getString("name"); System.out.println("Id:" + id1 + ",name:" + name); } } catch (SQLException e) { e.printStackTrace(); }