Mybatis设计分析一

Mybatis进阶功能介绍_踩踩踩从踩的博客-CSDN博客

前言

前面文章主要针对mybatis的进阶的使用有了个大的了解,包括缓存自定义  以及开启二级缓存机制,以及如何达到多数据源,按照我之前的写法通过路由 去解决 不同的数据源的问题,当然可以,有些时候其实也不用这么麻烦 ,毕竟具体的业务 具体分析,roundRobinDataSouceProxy  这个方法就可以 随意去变换,不能固定一个思维;本篇文章会继续介绍 mybatis 的原理,通过分析mybatis的书写的sql来开始分析 整个 mybatis如何进运行,mybatis框架考虑到的是那些点。

Mybatis

一个半自动化的orm 框架( Object Relation Mapping)。    ORM(Object Relational Mapping)框架采用 元数据来描述对象与关系映射的细节,元数据一般采用 XML格式,并且存放在专门的对象一映射文件中。简单理解为一种框架的格式。

这也是 现代 编程 非常喜欢的方式,还是因为对于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 框架是一个数据访问层的框架,帮我们完成对象在数据库中的存、取工作。
为什么称为半自动化?
关系型数据库的操作是通过 SQL 语句来完成的, Mybatis 在帮我们做对象的存取时,需要我们提供对应的 SQL 语句,它不自动帮我们生成SQL 语句,而只帮我们完成:
1 对象属性到 SQL 语句参数的自动填充;
2 SQL 语句执行结果集到对象的自动提取;
所以称为半自动的。而我们了解的另一个 ORM 框架 Hibernate 则是全自动的。
半自动化的不足:我们得辛苦一点编写 SQL 语句。
半自动化的优点:我们可以完全把控执行的 SQL 语句,可以随时灵活调整、优化。
为什么要使用mybatis的原因。
1 mybatis 学习、使用简单
2 、半自动化的优点
都是为了提高生产效率,少写代码,少写重复代码!
参数设置代码、结果集处理代码、 JDBC 过程代码都会大量重复,毫无技术含量!

框架确切需求

1 、用户只需定义持久层接口( dao 接口)、接口方法对应的 SQL 语句。
2 、用户需指明接口方法的参数与语句参数的对应关系。
3 、用户需指明查询结果集与对象属性的映射关系。
4 、框架完成接口对象的生成, JDBC 执行过程。
其实 还有个  有缓存 呀  还有 分页呀  上  功能增强  这也是 这个框架上的需求。、
给用户提供的便利。

Mybatis上的设计

用户只需定义持久层接口(dao接口)、接口方法对应的SQL语句。

设计问题:  

 提供什么样的方式来让用户定义SQL语句,

 mybatis开发者肯定 采用注解 和 xml的方式,虽然有点马后炮 ,但是java大家都知道 就采用这两种方式最好

 XML:独立于代码,修改很方便(不需改代码)  注解:直接加在方法上,零xml配置。

SQL语句怎么与接口方法对应 还有 应不应该进行区分 开 增删改查

SQL语句可做增、删、改、查操作,是否要对SQL做个区分

jdbc 中对应有不同的方法 executeQuery executeUpdate
xml :设计增删改查的元素:  
<!ELEMENT insert(#PCDATA) >
<!ELEMENT update(#PCDATA) >
<!ELEMENT delete(#PCDATA) >
<!ELEMENT select (#PCDATA) >
注解:设计增删改查的注解: @Insert @Update @Delete @Select ,注解项定义 SQL
 并且SQL语句与接口方法对应
为元素定义一个 id id 的值为对应的类名 . 方法名
<insert id = "com.study.mybatis.sample.UserDao.addUser" >
     insert into t_user(id,name,sex,age) values(?,?,?,?)
</insert>
一个 Dao 接口中可能会定义很多个数据访问方法, id 这么写很长,能不能便捷一点?
这是在做 SQL 与接口方法的映射,我们来加一个 mapper 元素,它可包含多个 insert update delete select 元素,相当于分组,一个接口中定义的分到一组。
mapper 中定义一个属性 namespace ,指定里面元素的名称空间, namespace 的值对应接口类名,里面元素的 id 对应方法名。

这个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语句、对应关系我们框架需要获取到,谁来获取?又该如何表示存储

xml 方式:
解析 xml 来获取
注解方式:
读取注解信息
@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);
1.怎么表示
得设计一个类来表示从 xml 、注解获得的 SQL 映射信息。

id为唯一id.

xml 方式: id=namespace.id 属性值
注解方式: id= 完整类名 . 方法名

2.怎么存储得到的 MappedStatement   这样的是 有多个 的  怎么样快速获得。
其实就是一个配置信息,我们定义一个 Confifiguration 类:

其实 是将 所有的 mappedstatement都存储起来。

key MappedStatementid  

3 、得有类来负责解析 xml

XmlMapperBuilder 负责解析 xml 文档( parse 方法的 resource 参数用来指定 inputStream 的来源),它调用 XMLStatementBuilder 来解析里面的
是不是感觉很像 spring  框架, 这些框架 其实都很像的。
4.mapper 中可以让用户如何来指定文件位置

 文件可以是在类目录下,也可是在文件系统目录下。

规定:
类目录下的方式通过 resource 属性指定;
文件系统文件通过 url 属性指定,值采用 URL 本地文件格式指定: fifile:///   
也就是 我们在 设置 sqlsessionfactory     需要设置 mapperlocation的含义。
<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 >
增加了一个 confifig xml 文件,就的有类来解析它。
增加解析 mybatis-confifig.xml 配置文件的类

注解的方式需要获取SQL映射信息,也得有个类来做这件事 

 谁来使用MapperAnnotationBuilder 进行解析 

Confifiguration 吧,在它里面持有 MapperAnnotationBuilder ,增加添加 Mapper 接口类的方法。

用户如何来指定Mapper接口类

mybatis-confifig.xmlmappers中通过mapper指定

<configuration>
<mappers>
<mapper resource="com/mybatis/UserMapper.xml"/>
<mapper url="file:///var/mappers/CourseMapper.xml"/>
 <mappers>
</configuration>
mapper 加一个属性 class 来专门指定 Mapper 类名
<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肯定是指定包名进行  指定的 

指定一个包名,包含包下所有接口、子孙包下的接口类
mappers 元素中增加一个 package 元素, pacakge 元素定义三个属性
mybatis-confifig.dtd
<!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>
为了用户使用方便,我们给定义一个 @Mapper 注解,默认规则:指定包下加了 @Mapper 注解的接口

 扫描就知道了。  这是mybatis给我们提供的方式。

加了 package 元素,又得在 Confifiguration 中增加对应的方法了: 
最开始 mybatis采用xml进行 一一对应的,接口 就有具体的实现类。都会有

 约定俗成的规则:指定包下扫到的@Mapper接口,例如UserDao,还可以在包下定义 UserDao.xml,会被加载解析。

用户需指明接口方法的参数与语句参数的对应关系。

 语句参数指定

@Mapper 
public interface UserDao {
 @Insert("insert into t_user(id,name,sex,age) values(?,?,?,?)") 
 void addUser(User user); 
}

这里 主要是  

User 对象的属性如何与 values(?) 对应?
靠解析 t_user(id,name,sex,age) 可行吗?
如果不添加别名 肯定不知道怎么将值1对1进行  对应起来。
这里需要个名称,交给用户去设置。
#{ 属性名 } 代替,我们来解析 SQL 语句中的 #{ 属性名 } 来决定参数对应
完全可以要求用户必须与参数名对应 : #{xname} 。 
为了提高点自由度(及后面方便 SQL 复用),可以定义一个注解让用户使用,该注解只可用在参数上

UserOrg中都有id属性,name属性

 

 如果方法参数是对象,则以 参数名.属性.属性 的方式指定SQL参数

 还是得根据名字来区分开  属性名称。

对于map的话还是一样的 key  map.key  都可以一样的。

order by #{orderColumn} order by 可以吗?
不可以,也就是说 方法参数不全是用来做 SQL 语句的预编译参数值的,有些是来构成 SQL 语句的一部分的。

对于预编译的情况 

一样,定义个 规则: ${ 属性名 } 表示这里是字符串替换都是 可以 

SQL中参数映射解析

SQL 中参数映射解析要完成 的是
解析出真正的 SQL 语句
获得方法参数与语句参数的对应关系 : 问号N--- 哪个参数值
至于怎么 执行 一个mapper接口
SqlSession
SqlSessionFactory
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踩踩踩从踩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值