1 Mybatis介绍
Mybatis是Apache下的一个开源的免费的半自动化的ORM框架,前身名叫IBatis
优势:简化了对数据库的操作,让程序员专注于对sql的编写,不再将大量的时间放在业务逻辑上
//模糊查询时,条件的不同会有不同的业务,此处的业务代码会非常的繁琐,可以使用Mybatis中的动态sql处理
String sql = "select * from t_user limit ?,?";
if(user0!=null) {
if(user0.getUname()!=null) {
sql = "select * from t_user where uname like concat('%',?,'%') limit ?,?";
ps = conn.prepareStatement(sql);
ps.setString(1, user0.getUname());
ps.setInt(2, pageCount*(pageIndex-1));
ps.setInt(3, pageCount);
}
}else {
ps = conn.prepareStatement(sql);
ps.setInt(1, pageCount*(pageIndex-1));
ps.setInt(2, pageCount);
}
ORM:持久化,例如:数据的存储等
半自动化:程序员可以自己编写对应的sql
问题:随着社会的发展及医疗等等的提升,现在社会人口的老龄化日趋严重、消费的方式等等的多样化,每个人对应的数据量也就越来越多,对应的需求方式也就更加的多样化
对比Hibernate框架,全自动的ORM框架,它的sql是自动生成的,程序员不能自己控制
面试题:Hibernate和Mybatis的区别—框架选型的时候为什么要选Mybatis
2 JDBC操作数据库存在的问题
问题1:在使用JDBC操作时,需要频繁的链接和关闭数据库
方案:使用数据库连接池进行管理 c3p0、druid等
硬编码和软编码的区别:
int a = 1;
int b = 2;
if(a == 2){}//如果用到的是常量值--硬编码
if(a == b){}//使用的两个变量的值都是可变的---软编码
问题2:存在大量的硬编码--如果sql存在问题,那就需要修改sql,只要修改了Java的代码,那就需要重新编译
方案:将所有的sql语句放在配置文件中(xml)
问题3:结果集处理存在大量的重复性工作,不利于后期的维护
方案:指定映射规则,将查询的结果集与实体类中的属性进行映射
问题4:条件的不同,会带来不同的业务需求,不利于后期的维护
方案:使用动态sql
面试题:Mybatis的实现原理
利用反射及xml解析实现
3 Mybatis的执行原理
面试题:简单描述下Mybatis的执行流程
回答:mybatsi是一个半自动化的ORM框架,通过SqlMapConfig.xml文件配置数据源和映射文件等,然后通过SqlSessionFactory对象创建SqlSession对象,执行sql语句,处理结果集
4 Mybatis入门案例
步骤:
1、导入jar包 mybatis.jar mysql-connector-java.jar log4j.jar
2、创建配置文件 配置数据源、加载映射文件
3、三层结构 对应要实现的业务
4、创建映射文件 具体要实现的功能对应的sql语句
查询列表
//查询所有的用户
@Test
public void testQueryUsers() throws IOException {
//1、自动从资源文件的根目录下进行查找
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//执行对应的功能
List<User> userList = sqlSession.selectList("test.queryUsers");
System.out.println(userList);
//4、关闭sqlSession对象
sqlSession.close();
inputStream.close();
}
查询指定ID的信息
//查询指定ID的用户
@Test
public void testQueryUserById() throws IOException {
//1、自动从资源文件的根目录下进行查找
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//执行功能 参数一:指定要执行的映射文件中对应的sql,参数二:要传递的参数值
User user = sqlSession.selectOne("test.queryUserById", 1);
System.out.println(user);
//4、关闭sqlSession对象
sqlSession.close();
inputStream.close();
}
selectOne和selectList
selectOne是查询单条语句使用的,selectList用于查询多条语句,会自动识别返回的数据条数。
可以使用selectList接收selectOne的结果,但是不能使用selectOne去接收selectList的结果
JUnit说明
JUnit:单元测试,可以单独运行指定的方法,不需要通过主函数,通常用于测试某个功能模块
使用:将JUnit的jar包添加到项目中
1、下载JUnit的jar包放到lib目录中右键关联到项目中
2、在项目中右键添加jar包,找到JUnit选择JUnit4添加到项目中即可
注意:方法不能静态的、方法不能有参数
//@Before修饰的方法,会在所有@Test方法执行前执行
@Before
public void before() throws IOException {
//1、自动从资源文件的根目录下进行查找
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
sqlSession = factory.openSession();
}
//@After修饰的方法会在所有@Test方法执行完后执行
@After
public void close() throws IOException {
//关闭连接
sqlSession.close();
inputStream.close();
}
添加用户信息
//注意点:对于增删改的操作因为修改了数据库的内容,所以需要进行事务提交,保证数据的一致性
//添加用户
@Test
public void testInsertUser() throws IOException {
//1、自动从资源文件的根目录下进行查找
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//执行添加的动作 参数一:指定对应要执行的sql,参数二:需要传递的参数
User user = new User();
user.setUname("郭某某");
user.setPhone("12378945699");
user.setAddress("郑州市二七区");
user.setUpwd("110");
user.setHireDate(new Date());
int result = sqlSession.insert("test.insertUser", user);
System.out.println("执行结果---->"+result);
//提交事务
sqlSession.commit();
//关闭sqlsession和流对象
sqlSession.close();
inputStream.close();
}
修改用户信息
@Test
public void testUpdateUser() throws IOException {
//1、自动从资源文件的根目录下进行查找
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//设置要修改的值
User user = new User();
user.setUid(22);
user.setPhone("78945612311");
user.setUpwd("120");
user.setAddress("the people in the earth");
int result = sqlSession.update("test.updateUser", user);
System.out.println("执行结果--->"+result);
//提交事务
sqlSession.commit();
//关闭连接
sqlSession.close();
inputStream.close();
删除指定用户信息
@Test
public void testDelUser() throws IOException {
//1、自动从资源文件的根目录下进行查找
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3、创建SqlSession对象
SqlSession sqlSession = factory.openSession();
//执行对应的sql
int result = sqlSession.delete("test.delUser", 22);
System.out.println("执行结果--->"+result);
//提交事务
sqlSession.commit();
//关闭连接
sqlSession.close();
inputStream.close();
}
配置别名
<typeAliases>
<!--
如果有多个实体类需要定义别名,那就写多个typeAlias
type指定类型 alias:指定对应的别名
-->
<!-- <typeAlias type="cn.yunhe.beans.User" alias="user"/> -->
<!-- 为了方便,也可以批量设置别名
指定要设置别名的实体类所在的包即可,它们的别名默认是类名(首字母不区分大小写 user/User)
-->
<package name="cn.yunhe.beans"/>
</typeAliases>
Mapper代理
思考问题:使用框架后,如何做到将查询出来的结果字段与对应的实体类中的属性进行一对一的映射?
前提是:需要知道实体类中到底有哪些属性存在(反射),通常实体类中的属性名和数据库中的字段名是保持一致的,这样的话,查询到的数据就可以直接进行映射,如果说查询到的字段(别名)和实体类中的属性名不一致,此时可以使用resultMap做映射关系处理(后面讲)
原始Mybatis开发中存在的问题:
1、存在硬编码的问题
2、代码臃肿问题
3、调用方法及参数类型不清晰
mapper代理开发的要求:
a、映射文件中的id值要和接口中的方法名保持一致
b、映射文件中的参数类型要和接口中的对应方法的参数列表一致
c、映射文件中的返回值类型要和接口中对应的方法的返回值类型保持一致
在mapper代理的基础上使用了批量加载映射文件的操作,需要再满足以下要求
d、映射文件的名字要和接口名一样
e、映射文件要和接口在同一个包下
注意:多个mapper文件存在时,namespace的值不能相同,通常用接口的全限定名来作为唯一标识
<mapper namespace="cn.yunhe.dao.IUserMapper">
<!--
id:作为唯一标识
parameterType:指定参数的类型,基本数据类型都支持,可以直接用,只能写一个参数类型
resultType:指定返回值的类型-包名+类名
注意点:sql语句的结尾不能有分号
#{val} 占位符,参数名可以任意写。如果参数类型是引用数据类型(对象),参数名要和实体类中的属性名对应
-->
<select id="queryUsers" resultType="User">
select uid,uname,upwd,phone,address,hireDate from t_user
</select>
<!-- 查询指定ID的用户信息 -->
<select id="queryUserById" parameterType="int" resultType="user">
select uid,uname,upwd,phone,address,hireDate from t_user where uid=#{uid}
</select>
</mapper>
@Test
public void testQueryUsers() throws IOException {
IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
List<User> userList = userMapper.queryUsers();
System.out.println(userList);
}
@Test
public void testQueryUserById() throws IOException {
IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
}
批量加载为了目录更加清晰,可以再创建一个资源文件夹与src的功能一样,用于存放相关的配置文件
测试结果