SQL注入
通过SQL代码的漏洞,进行攻击系统
例:在查询条件中输入‘’‘or 1 or’” 那么查询条件会显示的结果
[id=002, username=wangwu, salary=7898.0, age=23, depart=manage]
如何解决:数据厂商的问题
解决方案:
- 对Java语言中传递的字符串做预处理
- PrepareStatement:先由PrepareStatement 和数据库连接,对字符串进行预处理,处理结束后再去执行SQL
PrepareStatement的使用:
public static void main(String[] args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
//此处JDBCUtil是自己封装过的
conn = JDBCUtil.getConnection();
//定义SQL查询语句
String sql = "select * from tb1 where username=?";
//Statement无法处理,使用prepareStatement
ps = conn.prepareStatement(sql);
//此处1代表指向前面第几个问号,后面对应其值
ps.setString(1,"'or 1 or'");
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("username")+"\t"+rs.getInt("age")+"\t"+rs.getFloat("salary"));
}
}catch (SQLException e){
e.printStackTrace();
}
}
Statement与PreparedStatement的区别
- Preparedstatement是预处理过的,对于批量处理可以大大提高效率
- 数据库只进行一次处理时,用Statement对象进行处理,Preparedstatement开销比Statement大,对于一次性操作无好处
- Statement每次执行SQL语句时,相关数据库都要执行SQL的编译,PrepareStatement是预编译的,支持批处理
- Preparedstatement对象可以防止SQL注入更加安全。
Properties
在Java.util包中,它表示的是Java语言的配置文件,是Java语言独有的配置文件。 配置文件有很多中:
XML 文件 — 配置文件 Properties 的父类是HashTable
Properties 配置文件 — 一类问价 读取文件肯定是要用流的技术,使用流读取文件时把文件的内容读取到流中。
HashTable与HashMap的区别:
1.线程安全:HashTable是线程安全的,而HashMap线程不安全
2.null值:HashMap的key可以为null,而HashTablekey不可以为空
3.继承父类:HashTable继承的是Dictionary,而HashMap继承AbstractMap,但均实现Map接口
4.初始容量:HashTable初始容量为11,HashMap为16,两者默认填充因子均为0.75
5.判断键值是否存在:HashMap用ContainsKey(),而HashTable用get()方法。
Properties里存放键值对
driverCLassname=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
user=root
password=123456
static{
try{
Properties p = new Properties();
InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properities");
p.load(in);
driver = p.getProperty("driverCLassname");
url = p.getProperty("url");
user = p.getProperty("user");
password = p.getProperty("password");
Class.forName(driver);
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
static {
try {
Properties p = new Properties();
InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properities");
p.load(in);
driver = p.getProperty("driverCLassname");
url = p.getProperty("url");
user = p.getProperty("user");
password = p.getProperty("password");
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
PreparedStatement 封装方法
更新
public void Update(String sql,String...args){
try{
conn = getConnection();
ps = conn.prepareStatement(sql);
for(int i = 0; i<args.length(); i++){
ps.setObject(i+1,args[i]);
}
int bRet = ps.exectuteUpdate();
}catch (SQLException e){
e.printStackTrace();
}
}
多条语句查询
public <T> T query(Class<T> clazz,String sql,Object...args){
T entity = null;
PreparedStatement ps = null;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
//2. 得到 ResultSetMetaData 对象
ResultSetMetaData rsmd = rs.getMetaData();
//3. 创建一个 Map<String, Object> 列的名称 key 列的值作为value
Map<String, Object> values = new HashMap<>();
//4. 处理结果集. 利用 ResultSetMetaData 填充 对应的 Map 对象
if(rs.next()){
for(int i = 0; i < rsmd.getColumnCount(); i++){
//列的名称
String columnLabel = rsmd.getColumnLabel(i + 1);
//列多对应的value
Object columnValue = rs.getObject(i + 1);
values.put(columnLabel, columnValue);
}
}
//5. 若 Map 不为空集, 利用反射创建 clazz 对应的对象
if(values.size() > 0){
entity = clazz.newInstance();
//5. 遍历 Map 对象, 利用反射为 Class 对象的对应的属性赋值.
for(Map.Entry<String, Object> entry: values.entrySet()){
String fieldName = entry.getKey();
Object value = null;
if (entry.getValue() instanceof Long) {
value = Integer.parseInt(entry.getValue().toString());
}else{
value = entry.getValue();
}
ReflectionUtils.setFieldValue(entity, fieldName, value);
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return entity;
}