当前位置: 首页 > news >正文

Mybatis(2)

sql注入攻击

SQL注入攻击是一种常见的网络安全威胁,攻击者通过在输入字段中插入恶意SQL代码,绕过应用程序的安全机制,直接操纵数据库。

SQL注入的原理

SQL注入利用应用程序未对用户输入进行充分过滤或转义的漏洞。当用户输入被直接拼接到SQL查询中时,攻击者可以构造特殊输入,改变查询逻辑,获取未授权的数据或执行恶意操作。

-- 示例:通过输入' OR '1'='1绕过登录验证
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1';

SQL注入攻击是一种常见的网络安全威胁,攻击者通过在输入字段中插入恶意SQL代码,绕过应用程序的安全机制,直接操纵数据库。以下是关于SQL注入攻击的详细说明:

常见的SQL注入类型

基于错误的注入
攻击者通过故意引发数据库错误,从错误信息中获取数据库结构或敏感数据。

联合查询注入
利用UNION操作符将恶意查询结果合并到正常查询结果中,获取其他表的数据。

-- 示例:获取其他表数据
SELECT id, name FROM products WHERE id = 1 UNION SELECT username, password FROM users;

盲注
当应用程序不返回错误信息时,攻击者通过布尔条件或时间延迟判断查询结果。

-- 布尔盲注示例
SELECT * FROM users WHERE username = 'admin' AND SUBSTRING(password, 1, 1) = 'a';

防御SQL注入的方法

参数化查询(预编译语句)
使用参数化查询确保用户输入始终被视为数据而非代码。

# Python示例(使用SQLite)
import sqlite3
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

输入验证与过滤
对用户输入进行严格验证,仅允许符合预期的字符或格式。

最小权限原则
数据库账户应仅具有必要的最小权限,避免使用高权限账户连接数据库。

使用ORM框架
ORM(如Django ORM、SQLAlchemy)自动处理参数化查询,减少手动拼接SQL的需求。

# Django ORM示例
from django.db import models
User.objects.filter(username=username, password=password)

静态SQL与动态SQL的区别

静态SQL和动态SQL是数据库编程中两种不同的SQL语句处理方式,它们在编写方式、执行效率和适用场景上有显著差异。

静态SQL

静态SQL是指在程序编译时就已确定的SQL语句,通常直接嵌入在源代码中。这些语句的结构和参数在编译时已知,数据库管理系统(DBMS)可以预先优化。

特点

  • 语句在编译时固定,无法在运行时改变。
  • 性能较高,因为DBMS可以预编译和优化。
  • 通常用于参数化查询,参数通过占位符(如?@param)传递。

示例代码(Java中使用JDBC)

String sql = "SELECT * FROM employees WHERE department_id = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setInt(1, 10); // 设置参数
ResultSet rs = stmt.executeQuery();

动态SQL

动态SQL是指在程序运行时动态构建的SQL语句,通常根据用户输入或其他运行时条件生成。语句的结构或内容可能在运行时变化。

特点

  • 语句在运行时动态生成,灵活性高。
  • 性能较低,因为DBMS无法预编译。
  • 容易引发SQL注入风险,需谨慎处理输入。

示例代码(Java中使用JDBC)

String departmentId = getUserInput(); // 用户输入
String sql = "SELECT * FROM employees WHERE department_id = " + departmentId;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);

安全性与性能对比

静态SQL

  • 安全性高:参数化查询避免SQL注入。
  • 性能优:预编译减少运行时开销。

动态SQL

  • 安全性低:直接拼接输入可能导致注入。
  • 性能差:每次执行需重新解析和优化。

例子

数据库设计:

实体类代码:

package com.qcby.entity;public class student {private Integer id;private  String name;private  String sex;private  String phone;private  String password;private  Integer age;private Integer pageSize;private  Integer pageStart;public student() {}public student(String name, String sex, String phone, Integer age) {this.name = name;this.sex = sex;this.phone = phone;this.age = age;}public Integer getPageSize() {return pageSize;}public void setPageSize(Integer pageSize) {this.pageSize = pageSize;}public Integer getPageStart() {return pageStart;}public void setPageStart(Integer pageStart) {this.pageStart = pageStart;}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 getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "student{" +"id=" + id +", name='" + name + '\'' +", sex='" + sex + '\'' +", phone='" + phone + '\'' +", password='" + password + '\'' +", age=" + age +'}';}
}

dao层代码

package com.qcby.dao;import com.qcby.entity.student;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface  StudentDao {public  abstract List<student> findAll();student findById(Integer id);Integer delete(Integer id);List<student> findByName(String name);List<student> findBystudent(student student);Integer insert(student student);Integer insertGetId(student student);List<student> findAllStudent(Integer pageSize,Integer pageStart);List<student> findAllStudentByAge (student student);List<student> findUserByStudentName(String name);List<student> findUser(student student);int update(student student);List<student> selectUserByChoose(student student);List<student> selectUserByUsernameAndSex(student student);int trimUpdate(student student);int deleteMoreByArray(@Param("ids") Integer[] ids);int insertMoreByList(@Param("students") List<student> students);
}

mapper.xml代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.StudentDao"><select id="findAll" resultType="com.qcby.entity.student">SELECT * FROM student</select><select id="findById" resultType="com.qcby.entity.student" parameterType="java.lang.Integer">SELECT * from student WHERE id=#{id}</select><delete id="delete" parameterType="java.lang.Integer">DELETE from student WHERE id=#{id}</delete><select id="findByName" resultType="com.qcby.entity.student" parameterType="java.lang.String">SELECT  * from student where name=#{name}</select><select id="findBystudent" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">SELECT  * from student where name=#{name} and password=#{password}</select><insert id="insert" parameterType="com.qcby.entity.student">INSERT  INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})</insert><insert id="insertGetId" parameterType="com.qcby.entity.student"><selectKey keyProperty="id" resultType="int" order="AFTER">select LAST_INSERT_ID();</selectKey>INSERT INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})</insert><select id="findAllStudent" parameterType="java.lang.Integer" resultType="com.qcby.entity.student">SELECT * from student limit #{param1} offset #{param2}</select><select id="findAllStudentByAge" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student WHERE name=#{name} limit #{pageSize} offset #{pageStart}</select><select id="findUserByStudentName" parameterType="java.lang.String" resultType="com.qcby.entity.student">select * from student where name like #{value}</select><!-- where if --><select id="findUser" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><if test="name!=null and name!=''">AND name=#{name}</if><if test="sex!=null and sex!=''">AND sex=#{sex}</if><if test="phone!=null and phone!=''">AND phone=#{phone}</if><if test="password!=null and password!=''">AND password=#{password}</if><if test="age!=null and age!=''">AND age=#{age}</if></where></select><update id="update" parameterType="com.qcby.entity.student">UPDATE student<set><if test="name!=null and name!=''">name=#{name},</if><if test="sex!=null and sex!=''">sex=#{sex},</if><if test="phone!=null and phone!=''">phone=#{phone},</if><if test="password!=null and password!=''">password=#{password},</if><if test="age!=null and age!=''">age=#{age}</if></set>WHERE id = #{id}</update>
<!--if elseif else--><select id="selectUserByChoose" resultType="com.qcby.entity.student"            parameterType="com.qcby.entity.student">select * from student<where><choose><when test="name!=null and name!=''">AND name=#{name}</when><when test="sex!=null and sex!=''">AND sex=#{sex}</when><otherwise>and id=#{id}</otherwise></choose></where></select><select id="selectUserByUsernameAndSex" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">SELECT * from student<trim prefix="where" prefixOverrides="and | or"><if test="name!=null and name!=''">AND name=#{name}</if><if test="sex!=null and sex!=''">AND sex=#{sex}</if><if test="phone!=null and phone!=''">AND phone=#{phone}</if><if test="password!=null and password!=''">AND password=#{password}</if><if test="age!=null and age!=''">AND age=#{age}</if></trim></select>
<update id="trimUpdate" parameterType="com.qcby.entity.student">update student<trim prefix="set" suffixOverrides=","><if test="name!=null and name!=''">name=#{name},</if><if test="sex!=null and sex!=''">sex=#{sex},</if><if test="phone!=null and phone!=''">phone=#{phone},</if><if test="password!=null and password!=''">password=#{password},</if><if test="age!=null and age!=''">age=#{age},</if></trim>where id = #{id}
</update><!--delete from user where id in (1,2,3,4,5); --><delete id="deleteMoreByArray">DELETE FROM student WHERE id IN<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete><!-- collection:当前要循环的数组或者集合   --><!--  item: 我们指定要循环的数组的每一个元素  --><!-- separator:每一个元素应该用什么来做分割   --><!-- open:当前循环是以什么开始   --><!-- close:当前循环是以什么结束   --><!--insert into 表名 (字段) values (值),(值)--><insert id="insertMoreByList" >insert into student(name,age,sex,phone) values<foreach collection="students" item="student" separator=",">(#{student.name},#{student.age},#{student.sex},#{student.phone})</foreach></insert>
</mapper>

1. 基本结构与命名空间

<mapper namespace="com.qcby.dao.StudentDao">

这个标签确定了命名空间为com.qcby.dao.StudentDao,这意味着在 Java 代码里可以通过该命名空间来调用这些 SQL 映射语句。

2. 基础 CRUD 操作

  • 查询全部学生
    <select id="findAll" resultType="com.qcby.entity.student">SELECT * FROM student
    </select>
    
    此语句会返回student表中的所有记录。
  • 按 ID 查询学生
    <select id="findById" resultType="com.qcby.entity.student" parameterType="java.lang.Integer">SELECT * from student WHERE id=#{id}
    </select>
    
    它依据传入的 ID 参数来查找对应的学生。
  • 插入学生
    <insert id="insert" parameterType="com.qcby.entity.student">INSERT  INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})
    </insert>
    
    该语句用于向表中插入新的学生记录。
  • 更新学生信息
    <update id="update" parameterType="com.qcby.entity.student">UPDATE student<set><if test="name!=null and name!=''">name=#{name},</if><!-- 其他字段的更新条件类似 --></set>WHERE id = #{id}
    </update>
    
    借助<set>标签和<if>条件判断,能够动态地更新学生信息。
  • 删除学生
    <delete id="delete" parameterType="java.lang.Integer">DELETE from student WHERE id=#{id}
    </delete>
    
    此语句会删除指定 ID 的学生记录。

3. 动态 SQL 元素

  • <where>标签
    <select id="findUser" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><if test="name!=null and name!=''">AND name=#{name}</if><!-- 其他条件判断 --></where>
    </select>
    
    当有条件满足时,<where>标签会自动添加WHERE关键字,并且能智能地去除多余的ANDOR
  • <choose><when><otherwise>标签
    <select id="selectUserByChoose" resultType="com.qcby.entity.student" parameterType="com.qcby.entity.student">select * from student<where><choose><when test="name!=null and name!=''">AND name=#{name}</when><otherwise>and id=#{id}</otherwise></choose></where>
    </select>
    
    这组标签类似于 Java 中的switch-case语句,会按顺序进行条件判断,一旦有条件满足就会停止后续判断。
  • <trim>标签
    <update id="trimUpdate" parameterType="com.qcby.entity.student">update student<trim prefix="set" suffixOverrides=","><!-- 更新字段 --></trim>where id = #{id}
    </update>
    
    <trim>标签可以自定义前缀和后缀,suffixOverrides属性能够移除多余的逗号。

4. 批量操作

  • 批量删除
    <delete id="deleteMoreByArray">DELETE FROM student WHERE id IN<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>
    </delete>
    
    <foreach>标签会对集合进行遍历,可用于生成IN条件。
  • 批量插入
    <insert id="insertMoreByList" >insert into student(name,age,sex,phone) values<foreach collection="students" item="student" separator=",">(#{student.name},#{student.age},#{student.sex},#{student.phone})</foreach>
    </insert>
    
    利用<foreach>标签能够批量插入多条学生记录。

5. 分页查询

<select id="findAllStudent" parameterType="java.lang.Integer" resultType="com.qcby.entity.student">SELECT * from student limit #{param1} offset #{param2}
</select>

此查询通过limitoffset实现分页功能,param1代表每页的记录数,param2代表偏移量。

6. 自动获取主键

<insert id="insertGetId" parameterType="com.qcby.entity.student"><selectKey keyProperty="id" resultType="int" order="AFTER">select LAST_INSERT_ID();</selectKey>INSERT INTO student(name,sex,phone,password,age) VALUES (#{name},#{sex},#{phone},#{password},#{age})
</insert>

<selectKey>标签的作用是在插入数据后获取自动生成的主键,并将其赋值给实体类的id属性。

Test代码

import com.qcby.dao.StudentDao;
import com.qcby.dao.UserDao;
import com.qcby.entity.User;
import com.qcby.entity.student;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
public class StudentTest {private InputStream in = null;private SqlSession session = null;private StudentDao mapper = null;@Before  //前置通知, 在方法执行之前执行public void init() throws IOException {//加载主配置文件,目的是为了构建SqlSessionFactory对象in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//通过SqlSessionFactory工厂对象创建SqlSesssion对象session = factory.openSession();//通过Session创建UserDao接口代理对象mapper = session.getMapper(StudentDao.class);}@After  //@After: 后置通知, 在方法执行之后执行 。public void destory() throws IOException {//释放资源session.close();in.close();}@Testpublic void SELETALL(){List<student>  students = mapper.findAll();for (student student: students) {System.out.println(student.toString());}}@Testpublic  void findById(){student student=mapper.findById(1);System.out.println(student.toString());}@Testpublic void  delete(){mapper.delete(1);List<student>  students = mapper.findAll();for (student student: students) {System.out.println(student.toString());}session.commit();}@Testpublic  void findByName(){List<student> students=mapper.findByName("杨");for(student students1:students){System.out.println(students1.toString());}}@Testpublic void findBystudent(){student student=new student();student.setName("yu");student.setPassword("123456");List<student> students=mapper.findBystudent(student);for (student student1: students) {System.out.println(student1.toString());}}
@Testpublic  void insert(){student student=new student();student.setName("11");student.setPassword("123");student.setAge(11);student.setPhone("12345");student.setSex("男");mapper.insert(student);List<student>  students = mapper.findAll();for (student student1: students) {System.out.println(student1.toString());}session.commit();}@Testpublic  void insertGetId(){student student=new student();student.setName("11");student.setPassword("123");student.setAge(11);student.setPhone("12345");student.setSex("男");mapper.insertGetId(student);List<student>  students = mapper.findAll();for (student student1: students) {System.out.println(student1.toString());}session.commit();}@Testpublic void findAllStudent(){Integer pageSize=5;Integer pageIndex =1;Integer pageStart =pageSize *(pageIndex-1);List<student> students =mapper.findAllStudent(pageSize,pageStart);for(student student:students){System.out.println(student.toString());}}@Testpublic void findAllStudentByAge(){Integer pageSize=5;Integer pageIndex =1;student student=new student();Integer pageStart =pageSize *(pageIndex-1);student.setPageSize(pageSize);student.setName("博");student.setPageStart(pageStart);List<student> students =mapper.findAllStudentByAge(student);for(student student1:students){System.out.println(student1.toString());}}@Testpublic  void findUserByStudentName(){List<student> students=mapper.findUserByStudentName("%杨%");for(student student1:students){System.out.println(student1.toString());}}@Testpublic void findUser(){student student=new student();student.setSex("男");student.setPhone("1234321");student.setAge(11);student.setName("zzz");student.setPassword("123321");List<student> students=mapper.findUser(student);for(student student1:students){System.out.println(student1.toString());}}@Test
public void update(){student student=new student();student.setName("zzz");student.setId(2);student.setPassword("11441276423");student.setAge(143);student.setPhone("14231312");student.setSex("男");Integer num=mapper.update(student);List<student> students=mapper.findUser(student);for(student student1:students){System.out.println(student1.toString());}System.out.println(num);}@Test
public void selectUserByChoose(){student student=new student();student.setId(2);student.setName("bo");List<student>students=mapper.selectUserByChoose(student);for(student student1:students){System.out.println(student1.toString());}
}@Test
public  void  selectUserByUsernameAndSex(){student student=new student();student.setSex("男");student.setName("bo");List<student>students=mapper.selectUserByUsernameAndSex(student);for(student student1:students){System.out.println(student1.toString());}}@Test
public  void trimUpdate(){student student=new student();student.setName("sssssss");student.setId(2);mapper.trimUpdate(student);}@Testpublic void deleteMoreByArray(){Integer[] integer = new Integer[]{11,12,10,11};mapper.deleteMoreByArray(integer);session.commit();}@Testpublic void insertMoreByList(){student user1 = new student("小赵","男","1234",11);student user2 = new student("小张","男","122234",4);student user3 = new student("小李","男","123334",31);List<student> users = Arrays.asList(user1,user2,user3);mapper.insertMoreByList(users);session.commit();}}

单元测试基础

单元测试是验证代码最小单元(如函数、方法)行为的自动化测试。以下以Java的JUnit框架为例说明基本用法:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;public class CalculatorTest {@Testpublic void testAddition() {Calculator calc = new Calculator();assertEquals(5, calc.add(2, 3));  // 验证2+3=5}
}

测试注解类型

  • @Test:标记方法为测试用例
  • @BeforeEach:每个测试前执行初始化
  • @AfterEach:每个测试后执行清理
  • @BeforeAll / @AfterAll:全局初始化和清理(静态方法)

断言方法示例

import static org.junit.jupiter.api.Assertions.*;assertTrue(result > 0);          // 验证条件为真
assertNull(someObject);          // 验证对象为空
assertArrayEquals(expected, actual); // 验证数组相等

参数化测试

通过@ParameterizedTest实现多组输入测试:

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testIsPositive(int number) {assertTrue(number > 0);
}

测试覆盖率

使用工具(如JaCoCo)统计代码被测试覆盖的比例,通常建议达到80%以上关键路径覆盖率。在Maven项目中配置示例:

<plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.7</version><executions><execution><goals><goal>prepare-agent</goal></goals></execution></executions>
</plugin>

 Arrays.asList

Arrays.asList 方法

Arrays.asList 是 Java 中 java.util.Arrays 类提供的一个静态方法,用于将数组或可变参数转换为一个固定大小的列表(List)。该方法返回的列表是基于原始数组的视图,因此对列表的修改会影响原始数组,反之亦然。

语法
public static <T> List<T> asList(T... a)

使用示例

以下是一些常见的 Arrays.asList 用法示例:

示例 1:将数组转换为列表
String[] stringArray = {"apple", "banana", "cherry"};
List<String> stringList = Arrays.asList(stringArray);
System.out.println(stringList); // 输出: [apple, banana, cherry]
示例 2:直接传递可变参数
List<String> list = Arrays.asList("one", "two", "three");
System.out.println(list); // 输出: [one, two, three]

注意事项

  1. 固定大小列表
    返回的列表是固定大小的,不能添加或删除元素,否则会抛出 UnsupportedOperationException

    List<String> list = Arrays.asList("a", "b", "c");
    list.add("d"); // 抛出 UnsupportedOperationException
    
  2. 修改会影响原始数组
    由于返回的列表是原始数组的视图,修改列表中的元素会影响原始数组。

    String[] arr = {"a", "b", "c"};
    List<String> list = Arrays.asList(arr);
    list.set(0, "x"); // 修改列表
    System.out.println(arr[0]); // 输出: x
    

相关文章:

  • CPU飚高处理经验总结
  • Web前端开发(JS的快速入门)
  • AI要掌握的知识
  • RAGFlow与Dify的深度刨析
  • 矩阵乘法--Python
  • ES的Refresh、Flush、Merge操作对性能的影响? ES如何实现近实时(NRT)搜索? ES聚合查询的Terms和Cardinality区别?
  • Linux的读写屏障
  • Matlab实战训练项目推荐
  • 每日c/c++题 备战蓝桥杯(洛谷P1873 EKO砍树问题详解)
  • 打卡day35
  • 嵌入式开发之STM32学习笔记day10
  • DNS Server在高可用高并发系统中的应用
  • 探秘Transformer系列之(34)--- 量化基础
  • 【VBA中的集合(Collection)的引用和方法参数】 VS 字典(Dictionary)
  • 【无标题】python执行系统命令
  • Python 训练营打卡 Day 34
  • 基于Springboot + vue3实现的养老系统
  • 电子电路:再谈滤波原理及其应用
  • 卷积神经网络优化与应用实践:参数设置、泛化能力提升及多领域应用解析
  • LeetCode 3362.零数组变换 III:贪心+优先队列+差分数组——清晰题解
  • 网站的跳出率/动态网站的制作与设计
  • 如何创建网站挣钱/网站推广策划
  • 为什么最近好多网站打不开了/注册网站需要多少钱
  • 网站建设 2018/百度搜索推广收费标准
  • 二手商标网/网络seo是什么
  • dreamweaver做网站教学/手机app免费下载