文章目录
MyBatis介绍
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
简单来说,MyBatis 是一款持久层框架,底层很好的封装了JDBC的一系列操作,使用XML或注解的方式配置,使接口和POJO建立映射。
MyBatis环境
基于Maven项目,使用Maven坐标的方式。前往Maven仓库,可以找到你需要的大多数的资源。
当然如果你是传统的web项目使用MyBatis,需要创建并配置MyBatis.xml文件(该文件主要是数据库的dataSource数据源信息),并且在MyBatis.xml文件中为每一个xxxMapper.xml文件配置<Mapping>
标签让Mybatis知道如何寻找。
MyBatis使用步骤
下面的示范,基于传统的web项目举例。
- 引入Maven坐标
- 创建表
- 创建mybatis核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--环境配置,连接的数据库,这里使用的是MySQL-->
<environments default="mysql">
<environment id="mysql">
<!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<mappers>
<!--这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml-->
<mapper resource="mapper/userMapper.xml"></mapper>
</mappers>
</configuration>
- 创建实体类
public class User {
private int id;
private String name;
private int age;
//get/set方法省略
}
- 创建对应的xxxMapper接口
public interface UserMapper {
public User getUser(int id);
}
- 创建sql映射文件(xxxMapper.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.darian.mapper.UserMapper">
<select id="getUser" parameterType="int" resultType="com.darian.entity.User">
SELECT * FROM users where id =#{id}
</select>
</mapper>
- 检查MyBatis配置文件中是否配置了加载文件描述标签
<mappers>
,一个Mapper.xml一个<mapper>
标签
<mappers>
<mapper resource="mapper/userMapper.xml" />
</mappers>
- 自己测试(或Main方法测试)
public class Test {
public static void main(String[] args) throws IOException {
String resource = "mybatis.xml";
// 读取配置文件
Reader reader = Resources.getResourceAsReader(resource);
// 获取会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession openSession = sqlSessionFactory.openSession();
String sql = "com.darian.mapper.UserMapper.getUser";
User user = openSession.selectOne(sql, 1);
System.out.println(user.toString());
}
}
MyBatis之SQL注入
MyBatis的SQL注入,核心就是Mybatis在以:拼接核心参数的方式生成的SQL进行攻击。
比如一条传统的SQL语句是查询username,而有人通过sql注入将username=的值填写' OR 1=1 --
的方式,即:username=' OR 1=1 --
那么SQL就被注入攻击了。
因为–表示SQL注释,因此后面语句忽略;
因为1=1恒成立,因此 username=’’ OR 1=1 永恒成立。
解决SQL注入
在传统项目解决SQL注入问题:
采用?
号占位符方式+API对象PreparedStatement
,使得SQL预编译。核心示范步骤:
String sql = "SELECT name,pwd FROM user_table WHERE name=? AND pwd=?";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, name);
st.setString(2, pwd);
Mybatis中动态SQL中的#{}与${}区别
如果你不想知道其内部的思想,你只需要知道:优先使用 #{}。因为 ${} 会导致 sql 注入的问题即可。
以下具体案例说明,搬运于网络:
在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别:
select * from user where name = #{name};
select * from user where name = ${name};
其解析之后的结果均为
select * from user where name = 'zhangsan';
但是 #{} 和 ${} 在预编译中的处理是不一样的。#{} 在预处理时,会把参数部分用一个占位符 ? 代替,变成如下的 sql 语句:
select * from user where name = ?;
而 ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成
select * from user where name = 'zhangsan';
以上,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
那么,在使用过程中我们应该使用哪种方式呢?
答案是,优先使用 #{}。因为 ${} 会导致 sql 注入的问题。看下面的例子:
select * from ${tableName} where name = #{name}
在这个例子中,如果表名为
user; delete user; –
则动态解析之后 sql 如下:
select * from user; delete user; -- where name = ?;
"--
"之后的语句被注释掉,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机。
但是表名用参数传递进来的时候,只能使用 ${} ,具体原因可以自己做个猜测,去验证。这也提醒我们在这种用法中要小心sql注入的问题。
MyBatis注解
MyBatis的API提供了注解方式,使得我们不用创建Mappe.xml文件,得已在xxxMapper接口中的方法上使用注解和Mapper.xml文件的方式达到一样的效果,但是我并不推荐,首先sql的复杂和长度,其次是sql的统一管理在xml文件相比更加的清晰。
// 注解方式
public interface UserTestMapper {
@Select("select * from users where id = ${id};")
public User getUser(@Param("id") String id);
}
MyBatis 逆向工程,Generator
关于Generator,有非常多的方式,可以上网百度,适合自己的一种。
MyBatis的其他特性和玩法
MyBatis中文网,推荐阅读文档来了解框架是比较好的方式之一,关于Mybatis的相关问题都可以在官网找到答复。