前言
前面文章主要针对mybatis的进阶的使用有了个大的了解,包括缓存自定义 以及开启二级缓存机制,以及如何达到多数据源,按照我之前的写法通过路由 去解决 不同的数据源的问题,当然可以,有些时候其实也不用这么麻烦 ,毕竟具体的业务 具体分析,roundRobinDataSouceProxy 这个方法就可以 随意去变换,不能固定一个思维;本篇文章会继续介绍 mybatis 的原理,通过分析mybatis的书写的sql来开始分析 整个 mybatis如何进运行,mybatis框架考虑到的是那些点。
Mybatis
这也是 现代 编程 非常喜欢的方式,还是因为对于java编程来说,所有的操作 都采用 对象来获取这样的方式 是非常沉重的,而且代价是非常大。就像下面的方式一样。
@Component
public class UserDao {
@Autowired
private DataSource dataSource;
public void do1(String id, String name) {
System.out.println(id + name);
}
public void addUser(User user) throws SQLException {
try (
// 1、获取连接
Connection conn = DataSourceUtils.getConnection(dataSource);
// 2、创建预编译语句对象
PreparedStatement pst = conn.prepareStatement(
"insert into t_user(id,name,sex,age,address,phone,wechat,email,account,password) "
+ " values(?,?,?,?,?,?,?,?,?,?)");) {
// 3、设置参数值
int i = 1;
pst.setString(i++, user.getId());
pst.setString(i++, user.getName());
pst.setString(i++, user.getSex());
pst.setInt(i++, user.getAge());
pst.setString(i++, user.getAddress());
pst.setString(i++, user.getPhone());
pst.setString(i++, user.getWechat());
pst.setString(i++, user.getEmail());
pst.setString(i++, user.getAccount());
pst.setString(i++, user.getPassword());
// 4、执行语句
int changeRows = pst.executeUpdate();
}
}
public List<User> queryUsers(String likeName, int minAge, int maxAge, String sex) throws SQLException {
// 1、根据查询条件动态拼接SQL语句
StringBuffer sql = new StringBuffer(
"select id,name,sex,age,address,phone,wechat,email,account,password from t_user where 1 = 1 ");
if (!StringUtils.isEmpty(likeName)) {
sql.append(" and name like ? ");
}
if (minAge >= 0) {
sql.append(" and age >= ? ");
}
if (maxAge >= 0) {
sql.append(" and age <= ? ");
}
if (!StringUtils.isEmpty(sex)) {
sql.append(" and sex = ? ");
}
try (Connection conn = DataSourceUtils.getConnection(dataSource);
PreparedStatement pst = conn.prepareStatement(sql.toString());) {
// 2 设置查询语句参数值
int i = 1;
if (!StringUtils.isEmpty(likeName)) {
pst.setString(i++, "%" + likeName + "%");
}
if (minAge >= 0) {
pst.setInt(i++, minAge);
}
if (maxAge >= 0) {
pst.setInt(i++, maxAge);
}
if (!StringUtils.isEmpty(sex)) {
pst.setString(i++, sex);
}
// 3 执行查询
ResultSet rs = pst.executeQuery();
// 4、提取结果集
List<User> list = new ArrayList<>();
User u;
while (rs.next()) {
u = new User();
list.add(u);
u.setId(rs.getString("id"));
u.setName(rs.getString("name"));
u.setSex(rs.getString("sex"));
u.setAge(rs.getInt("age"));
u.setPhone(rs.getString("phone"));
u.setEmail(rs.getString("email"));
u.setWechat(rs.getString("wechat"));
u.setAccount(rs.getString("account"));
u.setPassword(rs.getString("password"));
}
rs.close();
return list;
}
}
}
采用jdbc的方式 去交互 。这里面 的缺点:
- 获取连接 不方便 自己封装连接池
- 使用方面 不方便 connection 用完了,关闭
- 事务的处理 ResultSet get结果 Object业务对象 怎么 关系 映射起来
- 某个表字段 关系型数据库 期望目标结果 Object对象
半自动 自己定义SQL语句 而会自动 映射到对象中 , 半自动的含义 就是 这点的区别 sql需要自定义 而 映射不用我们自己做。 自动映射 ,这也是 mybatis基于这个思想出来的。
对于hibernate上的区别。
现在 为了提高开发效率 有Mybatis-Generator 等工具 为我们的开发 提升效率 这也是找到 我们经常做的事情 而找到的规律,然后 自动 生成工具。 对于mybatis框架 更加 提升了。
灵活的写sql.
Mybatis完成的工作
框架确切需求
Mybatis上的设计
用户只需定义持久层接口(dao接口)、接口方法对应的SQL语句。
提供什么样的方式来让用户定义SQL语句,
mybatis开发者肯定 采用注解 和 xml的方式,虽然有点马后炮 ,但是java大家都知道 就采用这两种方式最好
XML:独立于代码,修改很方便(不需改代码) 注解:直接加在方法上,零xml配置。
SQL语句怎么与接口方法对应 还有 应不应该进行区分 开 增删改查
SQL语句可做增、删、改、查操作,是否要对SQL做个区分
<!ELEMENT insert(#PCDATA) ><!ELEMENT update(#PCDATA) ><!ELEMENT delete(#PCDATA) ><!ELEMENT select (#PCDATA) >
![](https://img-blog.csdnimg.cn/f301afd5322847fb9d1733db93833fae.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
<insert id = "com.study.mybatis.sample.UserDao.addUser" >insert into t_user(id,name,sex,age) values(?,?,?,?)</insert>
![](https://img-blog.csdnimg.cn/64dc3b095238401ebbbae65900d7288b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
这个xml文件命名为 userDaoMapper.xml,内容如下:
<mapper namespace="com.study.mybatis.sample.userDao">
<insert id="addUser">
insert into t_user(id,name,sex,age) values(?,?,?,?)
</insert>
</mapper>
截取最后一个点,根据方法名 进行 。
这些SQL语句、对应关系我们框架需要获取到,谁来获取?又该如何表示存储
@Insert("insert into t_user(id,name,sex,age) values(?,?,?,?)")
void addUser(User user);
@Select("select id,name,sex,age,address from t_user where sex = #{sex} order by #{orderColumn}")
List<User> query(String sex, String orderColumn);
void doSomething();
void do1(String name, String age);
![](https://img-blog.csdnimg.cn/11fe9e20c26e4e4c8bb603b997e35c7a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
id为唯一id.
![](https://img-blog.csdnimg.cn/4f129afb16764888911659d26dfd21a9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_19,color_FFFFFF,t_70,g_se,x_16)
其实 是将 所有的 mappedstatement都存储起来。
key 为MappedStatement的id
文件可以是在类目录下,也可是在文件系统目录下。
<configuration>
<mappers>
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper url="file:///var/mappers/CourseMapper.xml"/>
<mappers>
</configuration>
定义 mybatis-confifig.dtd
<!ELEMENT configuration ( mappers ?)+ ><!ELEMENT mappers ( mapper * )><!ELEMENT mapper EMPTY ><!ATTLIST mapper resource CDATA #IMPLIED url CDATA #IMPLIED >
![](https://img-blog.csdnimg.cn/94bdedea7deb4b07995b1854bbf81ee0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_16,color_FFFFFF,t_70,g_se,x_16)
注解的方式需要获取SQL映射信息,也得有个类来做这件事
谁来使用MapperAnnotationBuilder 进行解析
![](https://img-blog.csdnimg.cn/e4a0e5dfe5234eaa9250206adbf9bfc7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
用户如何来指定Mapper接口类
在mybatis-confifig.xml的mappers中通过mapper指定
<configuration>
<mappers>
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper url="file:///var/mappers/CourseMapper.xml"/>
<mappers>
</configuration>
<configuration>
<mappers>
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper url="file:///var/mappers/CourseMapper.xml"/>
<mapper class="com.study.mybatis.dao.UserDao" />
<mappers>
</configuration>
指定肯定不是 一个个 的指定,对于mybatis肯定是指定包名进行 指定的
<!ELEMENT configuration (mappers?)+ >
<!ELEMENT mappers (mapper*,package*)>
<!ELEMENT mapper EMPTY>
<!ATTLIST mapper
resource CDATA #IMPLIED
url CDATA #IMPLIED
class CDATA #IMPLIED
>
<!ELEMENT package EMPTY>
<!ATTLIST package
name CDATA #IMPLIED
type CDATA #IMPLIED
annotation CDATA #IMPLIED
>
<configuration>
<mappers>
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper url="file:///var/mappers/CourseMapper.xml"/>
<mapper class="com.study.mybatis.dao.UserDao" />
<package name="com.study.mybatis.mapper" />
<package name="com.study.mybatis.mapper"
type="com.study.mybatis.MapperInterface"/> <package
name="com.study.mike.mapper" annotation="com.study.mybatis.mybtis.annotation.Mapper"/>
<package name="com.study.mybatis.mapper"
type="com.study.mike.MapperInterface" annotation="com.study.mike.mybtis.annotation.Mapper"/>
<mappers>
</configuration>
扫描就知道了。 这是mybatis给我们提供的方式。
![](https://img-blog.csdnimg.cn/c3ed12e74b0e4ddbbaf9a1eaf198702d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Lip6Lip6Lip5LuO6Lip,size_20,color_FFFFFF,t_70,g_se,x_16)
约定俗成的规则:指定包下扫到的@Mapper接口,例如UserDao,还可以在包下定义 UserDao.xml,会被加载解析。
用户需指明接口方法的参数与语句参数的对应关系。
语句参数指定
@Mapper
public interface UserDao {
@Insert("insert into t_user(id,name,sex,age) values(?,?,?,?)")
void addUser(User user);
}
这里 主要是
![](https://img-blog.csdnimg.cn/5dc933397c88456fb1abb85931425d8b.png)
User和Org中都有id属性,name属性
如果方法参数是对象,则以 参数名.属性.属性 的方式指定SQL参数:
还是得根据名字来区分开 属性名称。
对于map的话还是一样的 key map.key 都可以一样的。
对于预编译的情况