Mybatis的介绍
mybatis就是一个封装来jdbc的持久层框架,它和hibernate都属于ORM框架,但是具体的说,hibernate是一个完全的orm框架,而mybatis是一个不完全的orm框架。
Mybatis让程序员只关注sql本身,而不需要去关注如连接的创建、statement的创建等操作。
Mybatis会将输入参数、输出结果进行映射。
Mybatis与Hibernate的区别及各自应用场景
Mybatis技术特点:
1、 通过直接编写SQL语句,可以直接对SQL进行性能的优化;
2、 学习门槛低,学习成本低。只要有SQL基础,就可以学习mybatis,而且很容易上手;
3、 由于直接编写SQL语句,所以灵活多变,代码维护性更好。
4、 不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
5、 需要编写结果映射。
Hibernate技术特点:
1、 标准的orm框架,程序员不需要编写SQL语句。
2、 具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。
3、 学习门槛高,需要对数据关系模型有良好的基础,而且在设置OR映射的时候,需要考虑好性能和对象模型的权衡。
4、 程序员不能自主的去进行SQL性能优化。
Mybatis应用场景:
需求多变的互联网项目,例如电商项目。
Hibernate应用场景:
需求明确、业务固定的项目,例如OA项目、ERP项目等。
分析JDBC的问题
1、 在创建连接时,存在硬编码
解决:配置文件(全局配置文件)
2、 在执行statement时存在硬编码
解决:配置文件(映射文件)
3、 频繁的开启和关闭数据库连接,会造成数据库性能下降。
解决:数据库连接池(全局配置文件)
Mybatis的框架原理
入门案例一
数据库
1.创建普通的Java项目,导入Mybatis的jar包、mysql驱动包以及Junit包
目录结构如下
2.关键的是Mybatis的全局配置文件(MybatisConfig.xml)以及映射文件(User.xml),文件命名无硬性要求
<!-- MybatisConfig.xml -->
<?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>
<!-- 加载java的配置文件或者声明属性信息 -->
<properties resource="db.properties">
<property name="db.username" value="root" />
<property name="db.password" value="root" />
</properties>
<!-- 配置mybatis的环境信息,与spring整合时,该信息由spring来管理 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源,采用mybatis连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="User.xml" />
</mappers>
</configuration>
<!-- User.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">
<!-- namespace:命名空间,对statement的信息进行分类管理 -->
<!-- 注意:在mapper代理时,它具有特殊及重要的作用 -->
<mapper namespace="User">
<!-- 根据用户ID查询用户信息 -->
<!-- select:表示一个MappedStatement对象 -->
<!-- id:statement的唯一标示 -->
<!-- #{}:表示一个占位符? -->
<!-- #{id}:里面的id表示输入参数的参数名称,如果该参数是简单类型,那么#{}里面的参数名称可以任意 -->
<!-- parameterType:输入参数的java类型 -->
<!-- resultType:输出结果的所映射的java类型(单条结果所对应的java类型) -->
<select id="findUserById" parameterType="int" resultType="com.zyj.mybatis.domain.User">
select * from user where id = #{id}
</select>
<!-- 根据用户名称模糊查询用户列表 -->
<!-- ${}:表示一个sql的连接符 -->
<!-- ${value}:里面的value表示输入参数的参数名称,如果该参数是简单类型,那么${}里面的参数名称必须是value -->
<!-- ${}这种写法存在sql注入的风险,所以要慎用!!但是在一些场景下,必须使用${},比如排序时,动态传入排序的列名,${}会原样输出,不加解释 -->
<select id="findUsersByName" parameterType="java.lang.String" resultType="com.zyj.mybatis.domain.User">
select * from user where username like '%${value}%'
</select>
<!-- 添加用户 -->
<!-- selectKey:查询主键,在标签内需要输入查询主键的sql -->
<!-- order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说 -->
<!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 -->
<insert id="addUser" parameterType="com.zyj.mybatis.domain.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
insert into user(username) values(#{username})
</insert>
<!-- 自增主键之UUID -->
<insert id="addUser2" parameterType="com.zyj.mybatis.domain.User2">
<!-- ID使用UUID时,order需要设置为BEFORE,否则无法在插入数据前获取UUID,结果ID为空,导致插入失败 -->
<selectKey keyProperty="id" resultType="string" order="BEFORE">
select uuid()
</selectKey>
insert into user2(id, username) values(#{id}, #{username})
</insert>
</mapper>
public class APITest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws IOException {
// 读取配置文件
String resource = "MybatisConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建sqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findUserByIdTest() throws IOException {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过sqlSession执行executor获取结果
// 第一个参数:表示statement的唯一标示
User user = sqlSession.selectOne("User.findUserById", 1);
System.out.println(user);
// 关闭资源
sqlSession.close();
}
@Test
public void findUserByNameTest() throws IOException {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过sqlSession执行executor获取结果
// 第一个参数:表示statement的唯一标示
List<Object> selectList = sqlSession.selectList("User.findUserByName", "小明");
System.out.println(selectList);
// 关闭资源
sqlSession.close();
}
@Test
public void addUserTest() throws IOException {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过sqlSession执行executor获取结果
// 第一个参数:表示statement的唯一标示
User2 user2 = new User2();
user2.setUsername("张育嘉");
sqlSession.insert("User.addUser2", user2);
System.out.println(user2.getId());
// 提交事务
sqlSession.commit();
// 关闭资源
sqlSession.close();
}
}
小结
#{}和${}
1.#{}表示占位符?,#{}接收简单类型的参数时,里面的名称可以任意
2.${}表示拼接符,${}接收简单类型的参数时,里面的名称必须是value
3.${}里面的值会原样输出,不加解析(如果该参数值是字符串,就不会添加引号)
4.${}存在sql注入的风险,但是有些场景下必须使用,比如排序后面会动态传入排序的列名
parameterType和resultType
1.parameterType指定输入参数的java类型,parameterType只有一个,也就是说入参只有一个。
2.resultType指定输出结果的java类型(是单条记录的java类型)
selectOne和selectList
1.selectOne查询单个对象
2.selectList查询集合对象