MyBatis是一个优秀的ORM(对象关系映射)框架,和Hibernate不太一样,Hibernate不用你编写一行SQL语句,而MyBatis需要手写SQL语句,优点就是能够灵活调试SQL语句。这篇文章主要对MyBatis的几个核心概念进行介绍,以及如何在项目中使用MyBatis。
MyBatis底层还是依赖JDBC来操作数据库,不过对JDBC的语法进行了封装,使用JDBC来操作数据库的流程一般是加载JDBC驱动->创建JDBC连接->创建Statement->执行查询->解析ResultSet->异常处理->关闭Statement和Connection,如果每次都这样做就比较繁琐。
MyBatis所有的数据库操作都是在SqlSession中操作,这样的话就可以缓存查询结果、不用重复创建JDBC连接。
顾名思义就是采用了Builder模式,用于创建SqlSessionFactory对象。
SqlSessionFactory工厂方法,用于创建SqlSession。
SqlSession 的实例不是线程安全的,每个线程都应该有它自己的SqlSession 实例,应该随着HttpServletRequest的创建而创建,请求结束则销毁。
承载了实际的业务逻辑,其生命周期比较短,由SqlSession创建,用于将Java对象和实际的SQL语句对应起来。
在开发过程中通常结合Spring框架一起使用提高开发效率,由于Spring进行了控制反转,所以其中MyBatis的初始化过程和正常过程稍稍有些不同:
Spring框架会在classpath下找到MyBatis的核心配置文件,使用它来初始化一个SqlSessionFactory实例。mapper类也会作为bean注入到代码中去的,Spring会使用上一步创建的SqlSessionFactory实例来创建SqlSession的实例,然后再使用SqlSession尝试创建各个mapper对象。
于此同时,MyBatis会扫描classpath下的mapper映射XML文件(此路径可以自定义),对于每一个mapper接口,它的「类全名」会作为命名空间,来和映射文件中的mapper标签进行匹配。
对于每一个映射文件中的一个执行语句标签(如select、delete),MyBatis会把他们映射到SqlSession的方法上,创建mapper接口的一个实现类。
如果mapper接口和其映射文件一一匹配,则bean创建成功。
下面的例子中首先创建了一个id为BaseResultMap的ResultMap,和Java模型数据的User相对应,并声明了数据库中列和模型的属性之间的对应关系,后面的Select语句可以引用这个ResultMap作为方法的返回值。然后创建了一个Base_Column_List的SQL语句,后面可以通过refid来引用这个SQL。具体的用法可以参考MyBatis文档
需要注意的是下面中的各个select、insert、update、delete的id需要和实际的com.ezlippi.mapper.UserMapper类中的方法一一对应。
<mapper namespace="com.ezlippi.mapper.UserMapper" >
<!--定义了Select语句返回结果和实际POJO对象的属性映射关系-->
<resultMap id="BaseResultMap" type="com.ezlippi.model.User" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="userName" property="userName" jdbcType="VARCHAR" />
<result column="passWord" property="passWord" jdbcType="VARCHAR" />
<result column="user_sex" property="userSex" javaType="com.ezlippi.enums.UserSexEnum"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR" />
</resultMap>
<!-- 定义了一条SQL语句模板,后面可以通过<include refid="Base_Column_List"/>引用这条SQL -->
<sql id="Base_Column_List" >
id, userName, passWord, user_sex, nick_name
</sql>
<select id="getAll" resultMap="BaseResultMap" >
SELECT
<include refid="Base_Column_List" />
FROM users
</select>
<select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
SELECT
<include refid="Base_Column_List" />
FROM users
WHERE id = #{id}
</select>
<insert id="insert" parameterType="com.ezlippi.model.User" >
INSERT INTO
users
(userName,passWord,user_sex)
VALUES
(#{userName}, #{passWord}, #{userSex})
</insert>
<update id="update" parameterType="com.ezlippi.model.User" >
UPDATE
users
SET
<if test="userName != null">userName = #{userName},</if>
<if test="passWord != null">passWord = #{passWord},</if>
nick_name = #{nickName}
WHERE
id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Long" >
DELETE FROM
users
WHERE
id =#{id}
</delete>
</mapper>
在拼接SQL语句中可以用"#{}"和"${}"来引用方法中的参数,两者的区别如下:
"#{}"在底层实现上使用?做占位符来生成PreparedStatement,然后将参数传入,大多数情况都应使用这个,它更快、更安全。
"${}"将传入的数据直接显示生成在sql中。如:order by ${user_id},如果传入的值是111,那么解析
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置dbcp数据源 引用jdbc.peoperties属性文件中的属性-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialPoolSize" value="${connection_pools.initial_pool_size}" />
<property name="minPoolSize" value="${connection_pools.min_pool_size}" />
<property name="maxPoolSize" value="${connection_pools.max_pool_size}" />
<property name="maxIdleTime" value="${connection_pools.max_idle_time}" />
<property name="acquireIncrement" value="${connection_pools.acquire_increment}" />
<property name="checkoutTimeout" value="${connection_pools.checkout_timeout}" />
</bean>
<!-- 配置mybatisSqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis.xml"/>
<property name="mapperLocations" value="classpath*:com/ezlippi/**/*Mapper.xml"/>
</bean>
<!-- 配置SqlSessionTemplate -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- mapper批量扫描,从mapper包中扫描出mapper接口,自动创建代理对象并且在spring容器中注册
遵循规范:将mapper.java和mapper.xml映射文件名称保持一致,且在一个目录 中
自动扫描出来的mapper的bean的id为mapper类名(首字母小写)
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ezlippi.**.dao"/>
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean>
<!-- 事务配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 使用annotation注解方式配置事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="com.ezlippi" />
<context:annotation-config />
</beans>
其中如下代码为spring自扫描所有dao包并把其下的所有mybatis接口文件装配入容器。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ezlippi.**.dao"/>
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
</bean>
mybatis配置文件mybatis.xml如下,主要配置一些alias:
<configuration>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
</typeAliases>
</configuration>
mybatis接口mapper需要加@Repository注解,方可直接在Service层直接自动装配注入。 mybatis接口mapper举例如下:
@Repository
public interface UserMapper {
List<User> getAll();
User getOne(Long id);
void insert(User user);
void update(User user);
void delete(Long id);
}
Service层注入mybatis接口mapper的时候需要在构造方法中注入,这样注入mapper实例才不会空。
@Service(value = "userService")
public class UserServiceImpl {
private UserMapper mapper;
@Autowired
public UserServiceImpl(UserMapper userMapper) {
this.mapper = userMapper;
}
public List<User> selectAll() {
return userMapper.selectAll();
}
}
看到这里,可能会有一个疑问,上面我只声明了UserMapper接口,没有定义实现类怎么调用具体的方法呢,别担心,mybatis通过JDK的动态代理方式,在启动加载配置文件时,根据配置mapper的xml去生成Dao的实现。
session.getMapper()使用了代理,当调用一次此方法,都会产生一个代理class的instance。
最后就是UserControl类了,调用UserService来完成具体的业务逻辑,
@RestController
public class UserControl {
@Autowired
private UserService userService;
@RequestMapping("/users/all")
public List<User> getAllUsers() {
return userService.selectAll();
}
}
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。