Mybatis
SqlSessionFactoryBuilder
通过SqlSessionFactoryBuilder创建会话工厂
将SqlSessionFactoryBuilder当成一个工具类使用,不需要使用单例管理SqlSessionFactoryBuilder。
在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。
SqlSessionFactory
通过SqlSessionFactory创建SQLSession,使用单例模式管理SqlSessionFactory(工厂一旦创建,使用一个实例,整个项目只有一个实例)
将来mybatis和Spring整合后,使用单例模式去管理SqlSessionFactory。
SqlSession
SqlSession是一个面向用户(程序员)接口
SqlSession提供了很多操作数据库的方法,
selectOne:返回单个对象,根据主键来查询
selectList:返回1个或者多个对象。
SqlSession是线程不安全,在SqlSession实现类中除了有接口中方法(操作数据库的方法),还有数据域属性。
SqlSession最佳应用场合是在方法体内,定义成局部变量使用。
原始DAO开发方法(DAO接口和DAO实现类)
编写:DAO接口、DAO 实现
DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置。
存在的问题
(1)dao接口实现类方法中,存在大量模板代码(重复),设想能否将这项代码抽取出来,大大减少程序员的工作量。
AOP思想;代理模式
(2)调用SQLSession方法的时候,传入的变量类型Object,即使变量类型传入错误,在编译阶段也不报错,不利于程序的开发。
Mapper代理开发方法(只需要写Mapper接口(相当于DAO接口))
程序员只需要编写Mapper接口(就相当于DAO),mybatis可以自动生成Mapper接口实现类对象。但是:要像自动生成实现类对象,需要遵循一些规范。
(1)Mapper接口和Mapper.xml放在同一个目录下。同名。
(2)Mapper.xml中namespace的值等于Mapper接口的全路径
(3)statementId,parameterType、ResultType和接口名字、入参类型、返回值类型要一致。
目录结构:
使用Mapper开发常见问题
(1)代理内部selectOne和selectList怎么区别的
根据接口的返回值来区别的。
如果返回值是POJO对象,selectOne来实现。
如果返回值是集合对象,selectList来实现。
(2)Mapper接口方法只能是一个参数
系统是否不利于扩展维护。
系统框架中,DAO层的代码是被业务层公用的
即使Mapper接口只有一个参数,可以使用包装类型的POJO满足不同业务方法的需求。
SQLMapConfig配置文件
可以配置内容和属性
properties(属性)
mybatis将按照下面的顺序来加载属性
(1)在properties元素内体定义的属性首先会被读取。
(2)然后会读取properties元素中resource或者URL加载的属性,它会覆盖已经读取同名的属性。
(3)最后读取parameterType传递的属性,它会覆盖已经读取同名的属性。
结构
配置resource中的sqlmapconfig.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>
<properties resource="db.properties">
<property name="jdbc.password" value="12"></property>
<property name="xxxid" value="1"></property>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zly/d_sql_map_config/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
配置UserMapper.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.zly.c_dao_mapper.mapper.UserMapper">
<!--查询用户列表:主键查询-->
<select id="findUserById" parameterType="int" resultType="com.zly.c_dao_mapper.pojo.User">
select * from user where id = #{id}//根据id查找用户
</select>
</mapper>
测试:
public class Demo01 {
private SqlSessionFactory sqlSessionFactory;
@Before
public void fun0() throws IOException {
InputStream inputStream = Resources.getResourceAsStream( "sqlMapconfig.xml" );
//通过配置创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
}
@Test
public void fun1() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper( UserMapper.class );
User user = userMapper.findUserById( 1 );
System.out.println(user);
}
}
结果:
建议:
(1)不要在properties元素体内添加任何属性值,只将属性值定义到properties文件中。
(2)在properties文件定义的属性名要有一定的特殊性,不能和系统,其他框架的名字重复。
xxx.yyy
jdbc.url
redis.url
settings(全局配置参数)(了解)
mybatis全局配置参数
setting 标签的配置是配置 MyBatis 框架运行时的一些行为的,例如缓存、延迟加载、结果集控制、执行器、分页设置、命名规则等一系列控制性参数,其所有的 setting 配置都放在父标签 settings 标签中。
setting可以配置的参数很多,做了解就行,当要用到的时候可以查资料。
typeAliases(类型别名)
在Mapper.xml中,定义了很多statement,statement需要parameterType指定输入参数的类型和resultType指定结果映射的类型。
如果在指定类型的时候,写“全路径”不大方便开发,可以针对parameterType和resultType指定的类型提供别名,在Mapper.xml中使用别名。
系统已经定义的别名
自定义别名:
定义单个别名:
批量定义:
typeHandlers(类型处理器)
由于数据库厂商的不同,所以厂商设置的参数可能也不同,同时数据库也可以自定义数据类型,typeHandler允许我们根据项目的需要自定义设置Java传递到数据库的参数中,或者从数据库读取数据,我们也需要进行特殊的处理,这些都可以在在定义的typeHandler中进行处理,尤其是在使用枚举的时候我们常常需要使用typeHandler进行转换。
mybatis中通过typeHandlers完成JDBC类型和Java类型的转换。
mappers(映射器)
在mybatis下mapper映射配置有四种方式:
通过resource加载,通过URL地址(使用完全限定路径,绝对路径),通过Mapper接口加载,批量加载(推荐)
批量加载时需要Mapper接口和Mapper映射文件放在同一个目录下面。并且遵循使用Mapper开发DAO的要求。
输入映射和输出映射
输入映射
Mybatis支持输入哪些类型
简单类型、POJO,HashMap,POJO的包装的类型。
需求:查询用户列表:已经下过订单男性用户,那么传入的参数包含用户信息(User)和订单信息(Order)
输出映射:
1.resultType
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
案例:
查找名字带“小”并且性别为男的用户。
mapper接口:
public interface UserMapper {
public List<User> findUserList(UserQueryVo userQueryVo);
}
mapper配置文件
<?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:命名空间,对SQL进行分类管理,SQL隔离-->
<mapper namespace="com.huadian.e_parameter_type_pojo.mapper.UserMapper">
<select id="findUserList" parameterType="com.huadian.e_parameter_type_pojo.vo.UserQueryVo" resultType="com.huadian.e_parameter_type_pojo.pojo.User">
select * from user where username like "%"#{user.username}"%" and sex = #{user.sex}
</select>
user实体类:
package com.huadian.e_parameter_type_pojo.pojo;
import java.util.Date;
public class User {
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
public User() {
}
public User(String username, String sex, Date birthday, String address) {
this.username = username;
this.sex = sex;
this.birthday = birthday;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" + "id=" + id + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", birthday=" + birthday + ", address='" + address + '\'' + '}';
}
}
user vo 类:
package com.huadian.e_parameter_type_pojo.vo;
import com.huadian.e_parameter_type_pojo.pojo.User;
public class UserQueryVo {
//用户信息
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
config.xml配置:
resultMap
(1)使用条件
Mybatis使用resultMap完成高级输出结果映射
当列名和属性名不一致的情况,自己来指定如何进行映射
动态SQL
需求(1):更新用户,前端修改了什么,SQL语句就包含哪些列
Update user set username=? where uid = ?
Update user set username=?,sex=? where uid = ?
Java 代码进行判断。
If(username ==null){
拼接SQL语句
}
需求(2):根据用户名和性别查询用户列表,
如果传递了用户名和性别,2个都作为条件
如果传递了用户名,没有传递性别,用户名作为条件
一个参数都没有传递,就没有条件
If和where
可以将 if 的 sql语句提出,这样在不同的语句中使用时可以调用,不需要写重复的代码。
Foreach:
foreach主要用在构建in条件中,它可以在SQL语句中迭代一个集合。它的属性主要有:item、index、collection、separator、close、open。
(1)item:表示集合中每个元素进行迭代时的别名。
(2)index:制定一个名称,用于表示在迭代过程中,每次迭代到的位置。
(3)open:表示该语句以什么开始(既然是in条件语句,所以必然以“(”开始)。
(4)separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是in条件语句,所以必须以“.”,作为分隔符)。
(5)close:表示该语句以什么语句结束(既然是in条件语句,所以必然是以“)”结束)。
(6)collection:最关键并最容易出错的属性,需格外注意,该属性必须指定,不同情况下,该属性的值是不一样的。