面试-3.MyBatis中#与$的区别,PrepareStatement

本文详细解析了MyBatis框架中#与$符号在SQL参数处理上的区别,强调了#作为预编译参数的安全性,对比${}

MyBatis中#与$的区别

0.c 防止sql 注入

举个例子:

	String sql = "select id from t_user where name =?";  

	PreparedStatement prep = conn.prepareStatement(sql);  
	prep.setString(1, name);  
    ResultSet rst = prep.executeQuery();  
  • 使用PrepareStatement时,SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析和编译,对应的执行计划也会缓存下来,之后数据库就会以参数化的形式进行查询。当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如上图中 or ‘1=1’,它也会作为一个字段的值来处理,而不会作为一个SQL指令。从根本上讲,其实就是data VS. code的问题,确保data永远是data,不会是可执行的code,就杜绝了SQL注入这种问题。
1.MyBatis

MyBatis中使用parameterType向SQL语句传参,parameterType支持的类型可以是基本类型int,String,HashMap和java自定义类型。

在SQL中引用这些参数的时候,可以使用两种方式:

  • #{parameterName}

  • ${parameterName}

mybatis对这两种参数的处理分为两个阶段,

     首先为构建sqlsessionFactory的时候,这个时候的处理为,如果sql中含有${}则该条sql不做处理,如果sql中全是#{}则替换为 ? 。

     然后是sqlSession执行sql阶段,该阶段首先会将${value} 原封不动的替换为 value传过来的值,然后在将sql中的#{} 替换为 ? 。

2.总结
  • ${} 会将传入的参数完全拼接到sql语句中,也就是相当于一个拼接符号。比如说 : String sql = select * from user where id=${value}
          最后的处理方式就相当于 MyBatis 会将 ${value} 完全替换为参数 value 的值。 相当replace("${value}", value)的过程。实际上mybatis 是先将sql转成char数组,然后截取 "KaTeX parse error: Expected '}', got 'EOF' at end of input: …的部分放入到容器,替换 以"{"开头 以 "}"结尾的内容。所以说它的作用相当于拼接符号。拼接后直接作为sql语句的一部分,所以如 果参数是可执行代码,sql是会直接执行的。这就是为什么它会导致sql注入。

  • #{} 是一个占位符, mybatis最后会将这个占位符,替换成?,最后才进行prepareStatement的相应位置的?的替换,也就是 state.setString(序号,值),setInt(序号,值)等。

使用#{}传递参数,被JDBC解析为PreparedStatement预编译语句,变量内容被当做一个整体变量,比如字符串,整形等。使用${}传递参数,纯粹是字符串替换,中间出现SQL语句,也会被正常执行。所以,在Mybatis中使用使用$传递参数时,需要考虑sql注入的问题。

Tips:
      ${}方式一般用于传入数据库对象,例如传入表名、字段名。
      排序时使用order by 动态参数时需要注意,用${}而不是 #{}。

<think>嗯,用户之前问过JVM调优的常用参数,现在又转向了Java和数据库相关的面试题。需要结合之前的对话和新的引用内容来生成相关的问题和答案。首先,用户提供的引用内容里提到了数据库事务的原子性、SQL查询的例子,以及Oracle和MySQL存储结构的区别。这可能暗示用户希望面试题涵盖事务、SQL操作、数据库引擎比较等方面。接下来,我需要确保回答符合用户的要求,包括结构清晰、使用中文、正确引用文献,并且生成相关问题。还要注意数学公式和代码块的格式,比如用$符号包裹行内公式,独立公式用$$,代码块用正确的语法高亮。用户之前的JVM问题涉及参数和调优,现在转向Java和数据库,可能需要涵盖JDBC、事务管理、连接池、ORM框架(如MyBatis和Hibernate)、数据库锁机制、SQL优化、索引、NoSQL等。同时,结合引用中的内容,比如事务的原子性,可以设计相关问题。另外,引用中提到的Oracle表空间和MySQL存储引擎的区别,也需要包括进去。需要确保每个问题都有对应的答案,并且答案中正确引用提供的引用内容。例如,在解释事务的ACID属性时,引用[1]中的原子性部分。在讨论MySQL存储引擎时,引用[3]的内容。SQL查询的例子可以参考引用[2]中的子查询。同时,生成的相关问题应该围绕Java和数据库的常见面试点,比如事务隔离级别、Spring事务管理、数据库连接池、索引优化、锁机制、ORM框架对比、分库分表策略等。还要注意用户可能需要的实际应用场景和问题解决方法,比如如何解决慢查询、如何处理事务失效等。最后,检查格式是否符合要求,数学表达式是否正确使用LaTeX,代码块是否正确标记语言,引用标识是否自然添加,以及是否生成了相关问题。确保没有使用任何Markdown格式,而是用纯文本实现结构清晰。</think>### Java数据库常见面试题解析 以下是Java数据库方向的典型面试题及解析,结合ACID事务原理、SQL优化和数据库引擎差异等核心知识点整理[^1][^3]。 --- #### **1. 事务的ACID特性是什么?** - **原子性(A)**:事务中的所有操作要么全部成功,要么全部失败回滚(如引用[1]中描述的撤销机制)。 - **一致性(C)**:事务执行前后数据库状态必须合法(如转账前后总金额不变)。 - **隔离性(I)**:并发事务之间互不干扰(通过锁或MVCC实现)。 - **持久性(D)**:事务提交后数据永久存储(通过日志持久化实现)[^1]。 --- #### **2. 如何优化SQL查询性能?** - **索引优化**:对WHERE、JOIN字段添加索引,避免全表扫描。 - **避免SELECT ***:仅查询需要的字段,减少数据传输量。 - **分页优化**:使用`LIMIT`或`ROW_NUMBER()`替代低效的`OFFSET`。 - **子查询优化**:如引用[2]中的子查询示例,可改写为JOIN操作: ```sql SELECT a.S# FROM SC a JOIN SC b ON a.S# = b.S# WHERE a.C#=&#39;001&#39; AND b.C#=&#39;002&#39; AND a.score > b.score; ``` --- #### **3. MySQL的InnoDBMyISAM引擎区别?** - **事务支持**:InnoDB支持ACID事务,MyISAM不支持(如引用[3]中对比)。 - **锁机制**:InnoDB支持行级锁,MyISAM仅表级锁。 - **外键**:InnoDB支持外键约束,MyISAM不支持。 - **存储结构**:InnoDB使用聚集索引(数据索引绑定),MyISAM使用非聚集索引。 --- #### **4. Java中如何防止SQL注入?** - **预编译语句(PreparedStatement)**: ```java String sql = "SELECT * FROM users WHERE username = ?"; PreparedStatement stmt = connection.prepareStatement(sql); stmt.setString(1, userInput); ``` - **避免拼接SQL**:禁止使用字符串拼接生成SQL语句。 - **ORM框架**:使用MyBatis/Hibernate的参数化查询。 --- #### **5. 数据库连接池的作用及参数配置** - **作用**:复用连接,减少频繁创建/销毁连接的开销。 - **关键参数**: - `maxPoolSize`:最大连接数(根据并发量设置)。 - `minIdle`:最小空闲连接数(避免突发请求延迟)。 - `maxWait`:获取连接的最大等待时间。 - **常见实现**:HikariCP、Druid。 --- #### **6. Spring事务失效的常见场景** - **非public方法**:`@Transactional`注解在非public方法上失效。 - **异常类型不匹配**:默认仅回滚`RuntimeException`,需通过`rollbackFor`指定。 - **同一类内方法调用**:AOP代理失效,需通过`AopContext.currentProxy()`调用。 --- #### **7. 数据库索引的B+树结构优势** - **范围查询高效**:叶子节点形成链表,适合范围扫描(如`WHERE id > 100`)。 - **高度平衡**:树高较低,减少磁盘I/O次数(对比B树)。 - **数据全在叶子节点**:非叶子节点仅存键值,可容纳更多分支。 --- ### 代码示例:JDBC事务管理 ```java Connection conn = dataSource.getConnection(); try { conn.setAutoCommit(false); // 关闭自动提交 Statement stmt = conn.createStatement(); stmt.executeUpdate("UPDATE account SET balance = balance - 100 WHERE user = &#39;A&#39;"); stmt.executeUpdate("UPDATE account SET balance = balance + 100 WHERE user = &#39;B&#39;"); conn.commit(); // 提交事务 } catch (SQLException e) { conn.rollback(); // 回滚事务 } finally { conn.close(); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值