Mybatis

  1. mybatis实战教程(mybatis in action),mybatis入门到精通
  2. W3Cschool:MyBatis 教程

Mybatis架构

Mybatis架构

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="jdbc.properties"/>
	<!-- 别名 包以其子包下所有类   头字母大小都行-->
	<typeAliases>
<!-- 		<typeAlias type="com.itheima.mybatis.pojo.User" alias="User"/> -->
		<package name="com.itheima.mybatis.pojo"/>
	</typeAliases>
	<!-- 和spring整合后 environments配置将废除    -->
	<environments default="development">
		<environment id="development">
			<!-- 使用jdbc事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
	
	<!-- Mapper的位置  Mapper.xml 写Sql语句的文件的位置 -->
	<mappers>
<!-- 		<mapper resource="sqlmap/User.xml" class="" url=""/> -->
<!-- 		<mapper resource="sqlmap/User.xml" class="" url=""/> -->
<!-- 		<mapper class="com.itheima.mybatis.mapper.UserMapper" /> -->
<!-- 		<mapper url="" /> -->
		<!-- 此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中 -->
		<package name="com.itheima.mybatis.mapper"/>
	</mappers>
</configuration>

UserMapper.xml
若User类属性与user表字段名字相同,mybatis可以完成结果集自动映射

<?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">
<!-- 写Sql语句   -->
<mapper namespace="com.itheima.mybatis.mapper.UserMapper">
	<!-- 通过ID查询一个用户 -->
	<select id="findUserById" parameterType="Integer" resultType="User">
		select * from user where id = #{v}
	</select>
	
	<!-- //根据用户名称模糊查询用户列表
	#{}    select * from user where id = ?    占位符  ? ==  '五'  会自动带上单引号(预编译),括号内填任意值
	${}    select * from user where username like '%五%'  字符串拼接   不带单引号,括号内只能填value.${value}.不防sql注入
	
	 -->
	<select id="findUserByUsername" parameterType="String" resultType="com.itheima.mybatis.pojo.User">
		select * from user where username like "%"#{haha}"%"
	</select>
	
	<!-- 添加用户 -->
	<insert id="insertUser" parameterType="com.itheima.mybatis.pojo.User">
		<selectKey keyProperty="id" resultType="Integer" order="AFTER">
			select LAST_INSERT_ID()
		</selectKey>
		insert into user (username,birthday,address,sex) 
		values (#{username},#{birthday},#{address},#{sex})
	</insert>
	
	<!-- 更新 -->
	<update id="updateUserById" parameterType="com.itheima.mybatis.pojo.User">
		update user 
		set username = #{username},sex = #{sex},birthday = #{birthday},address = #{address}
		where id = #{id}
	</update>
	
	<!-- 删除 -->
	<delete id="deleteUserById" parameterType="Integer">
		delete from user 
		where id = #{vvvvv}
	</delete>


</mapper>

?

	@Test
	public void testMybatis() throws Exception {
		//加载核心配置文件
		String resource = "sqlMapConfig.xml";
		InputStream in = Resources.getResourceAsStream(resource);
		//创建SqlSessionFactory
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
		//创建SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		//执行Sql语句 
		User user = sqlSession.selectOne("test.findUserById", 10);
		
		System.out.println(user);
	}

Mapper动态代理开发

?  原始Dao开发需要写Dao接口,DaoImpl实现类,调用session的selectOne/selectList/update/insert/delete方法,实现类中各方法本质上只有语句id和参数不同.而且还要在每个方法中调用SqlSessionFactory的openSession方法.因此会显得很繁琐.
  动态代理开发只需要写接口,实现类由Mybatis动态生成
  Mapper接口开发需要遵循以下规范:
   1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
   2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
   3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
   4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

public interface UserMapper {

	//遵循四个原则
	//接口 方法名  == UserMapper.xml 中 id 名
	//返回值类型  与  Mapper.xml文件中返回值类型要一致
	//方法的入参类型 与Mapper.xml中入参的类型要一致
	//命名空间 绑定此接口
	public User findUserById(Integer id);
	
}

?

	@Test
	public void testMapper() throws Exception {
		//加载核心配置文件
		String resource = "sqlMapConfig.xml";
		InputStream in = Resources.getResourceAsStream(resource);
		//创建SqlSessionFactory
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
		//创建SqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		//SqlSEssion帮我生成一个实现类  (给接口)
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		
		User user = userMapper.findUserById(10);
		System.out.println(user);
	}

 selectOne和selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

 namespace
mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

parameterType输入类型

Mybatis使用ognl表达式解析对象字段的值,#{}或${}中的值为pojo属性名称

传递简单类型
String Integer

传递pojo对象

传递pojo包装对象
  开发中通过pojo传递查询条件,条件可能是综合的查询条件,不仅包括用户查询条件还包括其他的查询条件,这时可以使用包装对象传递输入参数.
  包装对象:pojo类中的一个属性是另外一个pojo

根据用户名模糊查询(QueryVo对象中有一个User属性)
<select id="findUserByQuery" parameterType="QueryVo" resultType="User">
	select * from user where username like "%"#{user.username}"%"
</select>

resultType输出类型

输出简单类型

public Integer countUser();
<select id="countUser" resultType="Integer">
	select count(*) from user
</select>

输出pojo对象

<select id="findUserByUsername" parameterType="String" resultType="User">
	select * from user where username like "%"#{aa}"%"
</select>

输出pojo列表
同上,mybatis会根据返回数量决定返回单个user对象或是list

resultMap

如果sql查询字段名与pojo属性名不一致,可以通过resultMap将字段名和属性名做一个对应关系

public List<Orders> selectOrdersList();

<resultMap type="Orders" id="aaa">
	<!-- 若有部分字段名与属性名一致,可省略不写,自动映射 -->
	<id column="id" property="id"/>
	<result column="user_id" property="userId"/> 除此条外均可省略
	<result column="number" property="number"/>
	<result column="createtime" property="createtime"/>
	<result column="note" property="note"/>
</resultMap>
<select id="selectOrdersList" resultMap="aaa">
	select id, user_id, number, createtime, note from orders
</select>

?

动态sql

通过Mybatis提供的各种标签方法实现动态拼接sql

需求:根据性别和名字查询用户

if标签

public List<User> selectUserBySexAndUsername(User user);
<!-- 传来的user中sex和username可能为空 -->
<select id="selectUserBySexAndUsername" parameterType="User" resultType="User">
	select * from user 
	where 1 = 1
	<if test="sex != null and sex != ' '">
		and sex = #{sex} 
	</if>
	<if test="username != null and username != ' '">
		and username = #{username} 
	</if>
</select>

where标签
上面的sql还需要使用where 1=1 这样的语句,很麻烦,可以使用where标签进行改造

public List<User> selectUserBySexAndUsername(User user);
<!-- where标签可以去掉第一个前置and -->
<select id="selectUserBySexAndUsername" parameterType="User" resultType="User">
	select * from user 
	<where>
		<if test="sex != null and sex != ' '">
			and sex = #{sex} 
		</if>
		<if test="username != null and username != ' '">
			and username = #{username} 
		</if>
	</where>
</select>

sql标签
Mybatis中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的

<sql id="selectall">
	select * from user
</sql>

<select id="selectUserBySexAndUsername" parameterType="User" resultType="User">
	<include refid="selectall"/>
	<where>
		<if test="sex != null and sex != ' '">
			and sex = #{sex} 
		</if>
		<if test="username != null and username != ' '">
			and username = #{username} 
		</if>
	</where>
</select>

foreach标签
向sql传递数组或List,Mybatis使用foreach解析
需求:根据多个id查询用户信息
select * from user where id in (1,10,24)

若传递QueryVo包装类.collection填其数组或list的属性名

//public List<User> selectUserByIds(Integer[] ids);
//public List<User> selectUserByIds(List<Integer> ids);
public List<User> selectUserByIds(QueryVo vo);//QueryVo中含有数组或List属性

<select id="selectUserByIds" parameterType="QueryVo" resultType="User">
	<include refid="selectall"/>
	<where>
		id in
		<foreach collection="idsList" item="id" separator="," open="(" close=")">
			#{id}
		</foreach>
	</where>
</select>

若传递数组.collection=“array”(parameterType可不写??)

public List<User> selectUserByIds(Integer[] ids);

<select id="selectUserByIds" resultType="User">
	<include refid="selectall"/>
	<where>
		id in
		<foreach collection="array" item="id" separator="," open="(" close=")">
			#{id}
		</foreach>
	</where>
</select>

若传递集合list.collection=“list”(parameterType可不写??)

public List<User> selectUserByIds(List<Integer> ids);

<select id="selectUserByIds" resultType="User">
	<include refid="selectall"/>
	<where>
		id in
		<foreach collection="list" item="id" separator="," open="(" close=")">
			#{id}
		</foreach>
	</where>
</select>

关联查询

订单与用户
一对一查询
需求:查询所有订单信息,关联查询下单用户信息
select o.id, o.user_id, o.number, o.createtime, u.username from orders o left join user u on o.user_id = u.id

方法一:使用resultType
  新建一个OrderUser类继承Order类,OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可
  private String username
  
方法二:使用resultMap
  在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息.

//以订单为中心,关联用户
OrderMapper
public List<Orders> selectOrders();

<!-- 关联查询时,即使字段与属性名相同,也需要手动配置映射 -->
<resultMap id="zzz" type="Orders">
	<id column="id" property="id"/>
	<result column="user_id" property="userId"/>
	<result column="number" property="number"/>
	<!-- 一对一 -->
	<association property="user" javaType="User">
		<!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
		<id column="user_id" property="id" />
		<result column="username" property="username"/>
	</association>
</resultMap>

<select id="selectOrders" resultMap="zzz">
	select 
	o.id, 
	o.user_id,
	o.number, 
	o.createtime, 
	u.username 
	from orders o 
	left join user u 
	on o.user_id = u.id
</select>

一对多查询
需求:查询所有用户信息及用户关联的订单信息
select o.id, o.user_id, o.number, o.createtime, u.username from user u left join orders o on o.user_id = u.id
修改pojo类:在User类中加入订单属性
  private List<Orders> ordersList;

//以用户为中心,关联订单
public List<User> selectUserList();

<resultMap id="qqq" type="User">
	<id column="user_id" property="id"/>
	<result column="username" property="username"/>
	<!-- 一对多 -->
	<collection property="ordersList" ofType="Orders">
		<id column="id" property="id"/>
		<result column="number" property="number"/>
	</collection>
</resultMap>

<select id="selectUserList" resultMap="qqq">
	select 
	o.id, 
	o.user_id, 
	o.number, 
	o.createtime, 
	u.username 
	from user u 
	left join orders o 
	on o.user_id = u.id
</select>

Mybatis整合Spring

整合思路
1、SqlSessionFactory对象应该放到spring容器中作为单例存在
2、传统dao的开发方式中,应该从spring容器中获得sqlsession对象
3、Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象
4、数据库的连接以及数据库连接池事务管理都交给spring容器来完成

SqlMapConfig.xml

<configuration>
	<!-- 设置别名 -->
	<typeAliases>
		<!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 -->
		<package name="cn.itcast.mybatis.pojo" />
	</typeAliases>
</configuration>

applicationContext.xml

<!-- 加载配置文件 -->
	<context:property-placeholder location="classpath:db.properties" />

	<!-- 数据库连接池 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<property name="maxActive" value="10" />
		<property name="maxIdle" value="5" />
	</bean>

	<!-- 配置SqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 配置mybatis核心配置文件 -->
		<property name="configLocation" value="classpath:SqlMapConfig.xml" />
		<!-- 配置数据源 -->
		<property name="dataSource" ref="dataSource" />
	</bean>
</beans>

Dao开发
?
传统Dao的开发方式
原始的DAO开发接口+实现类来完成。
需要dao实现类需要继承SqlsessionDaoSupport
还需要在spring中为dao注入sqlSessionFactory属性

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
	@Override
	public User queryUserById(int id) {
		// 获取SqlSession
		SqlSession sqlSession = super.getSqlSession();

		// 使用SqlSession执行操作
		User user = sqlSession.selectOne("queryUserById", id);

		// 不要关闭sqlSession

		return user;
	}

	@Override
	public List<User> queryUserByUsername(String username) {
		// 获取SqlSession
		SqlSession sqlSession = super.getSqlSession();

		// 使用SqlSession执行操作
		List<User> list = sqlSession.selectList("queryUserByUsername", username);

		// 不要关闭sqlSession

		return list;
	}

	@Override
	public void saveUser(User user) {
		// 获取SqlSession
		SqlSession sqlSession = super.getSqlSession();

		// 使用SqlSession执行操作
		sqlSession.insert("saveUser", user);

		// 不用提交,事务由spring进行管理
		// 不要关闭sqlSession
	}
}

Mapper动态代理形式开发dao
方式一:配置mapper代理
  在applicationContext.xml添加配置
  MapperFactoryBean也是属于mybatis-spring整合包
  SqlMapConfig.xml中需要配置Mapper文件的包路径(方式二不用)

<!-- Mapper代理的方式开发方式一,配置Mapper代理对象 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<!-- 配置Mapper接口 -->
	<property name="mapperInterface" value="cn.itcast.mybatis.mapper.UserMapper" />
	<!-- 配置sqlSessionFactory -->
	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

方式二:扫描包形式配置mapper(建议)

<!-- Mapper代理的方式开发方式二,扫描包方式配置代理
	会自动找到容器中的工厂对象,无需手动注入
 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<!-- 配置Mapper接口的包路径 -->
	<property name="basePackage" value="cn.itcast.mybatis.mapper" />
</bean>

每个mapper代理对象的id就是类名,首字母小写

?

逆向工程

使用官方网站的Mapper自动生成工具mybatis-generator-core-1.3.2来生成pojo类,Mapper映射文件和Mapper接口
注意:
  1.逆向工程生成的代码只能做单表查询
  2.不能在生成的代码上进行扩展,因为如果数据库变更,需要重新使用逆向工程生成代码,原来编写的代码就被覆盖了
  3.一张表会生成4个文件
生成文件

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值