mybatis架构
sqlMapConfig.xml 是核心配置文件
mapper.xml是映射文件,sql写在这里
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>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.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>
</configuration>
创建pojo
Public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
get/set……
sql映射文件
<?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:命名空间,可以用于绑定接口,区分mapper文件 -->
<mapper namespace="test">
</mapper>
加载映射文件
<!-- 在MapConfig.xml中配置 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
</mappers>
根据id查询用户
<mapper namespace="test">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:声明输入参数的类型 -->
<!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
<!-- #{}:输入参数的占位符 -->
<select id="queryUserById" parameterType="int"
resultType="cn.test.mybatis.pojo.User">
SELECT * FROM `user` WHERE id = #{id}
</select>
</mapper>
测试
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory = null;
@Before
public void init() throws Exception {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
}
//或者直接写成
//String resource = "sqlMapConfig.xml";
//InputStream in = Resource.getResourceAsStream(resource);
//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//SqlSession sqlSession = sqlSessionFactory.openSession()'
@Test
public void testQueryUserById() throws Exception {
// 4. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
// 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
Object user = sqlSession.selectOne("test.queryUserById", 1);
// 6. 打印结果
System.out.println(user);
// 7. 释放资源
sqlSession.close();
}
}
根据用户名模糊查询用户
<!-- 如果返回多个结果,mybatis会自动把返回的结果放在list容器中 -->
<!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername2" parameterType="string"
resultType="cn.test.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE '%${value}%'
</select>
或者
<!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername2" parameterType="string"
resultType="cn.test.mybatis.pojo.User">
SELECT * FROM `user` WHERE username LIKE '%'#{value}'%'
</select>
<!-- ${} 字符串拼接,#{}是占位符,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
而${}不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 -->
测试
// 5. 执行SqlSession对象执行查询,获取结果User
// 查询多条数据使用selectList方法
List<Object> list = sqlSession.selectList("test.queryUserByUsername2", "王");
5.7. 实现添加用户
<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.test.mybatis.pojo.User">
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
测试
// 执行SqlSession对象执行保存
// 创建需要保存的User
User user = new User();
user.setUsername("aa");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("bb");
sqlSession.insert("test.saveUser", user);
System.out.println(user);
// 需要进行事务提交
sqlSession.commit();
// 7. 释放资源
sqlSession.close();
5.7.4. mysql自增主键返回
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.test.mybatis.pojo.User">
<!-- selectKey 标签实现主键返回 -->
<!-- keyColumn:主键对应的表中的哪一列 -->
<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
<!-- resultType:设置返回的id的类型 -->
<selectKey keyColumn="id" keyProperty="id" order="AFTER"
resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>
5.8. 修改用户
!-- 更新用户 -->
<update id="updateUserById" parameterType="cn.test.mybatis.pojo.User">
UPDATE `user` SET
username = #{username} WHERE id = #{id}
</update>
测试
// 执行SqlSession对象执行更新
// 创建需要更新的User
User user = new User();
user.setId(26);
user.setUsername("关羽");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("蜀国");
sqlSession.update("test.updateUserById", user);
删除用户
<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="int">
delete from user where
id=#{id}
</delete>
测试
// 5. 执行SqlSession对象执行删除
sqlSession.delete("test.deleteUserById", 48);
Mapper动态代理方式
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 class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception {
// 创建SqlSessionFactoryBuilder
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SqlsessionFactory
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() {
// 获取sqlSession,和spring整合后由spring管理
SqlSession sqlSession = this.sqlSessionFactory.openSession();
// 从sqlSession中获取Mapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行查询方法
User user = userMapper.queryUserById(1);
System.out.println(user);
// 和spring整合后由spring管理
sqlSession.close();
}
动态代理的方式,由sqlSession帮我们动态生成一个实现类,这种方式,sqlSession会根据返回值选择使用selectOne还是selectList
SqlMapConfig.xml配置文件
properties(属性)
<!-- 使用resource属性加载外部配置文件 -->
<properties resource="db.properties">
typeAliases(类型别名)
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.test.mybatis.pojo.User" />
<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
<package name="cn.test.mybatis.pojo" />
<package name="其它包" />
</typeAliases>
在mapper.xml配置文件中,就可以使用设置的别名了
别名大小写不敏感
mappers(映射器)
<mapper resource=" " />
//使用相对于类路径的资源(现在的使用方式)
<mapper resource="sqlmap/User.xml" />
<mapper class=" " />
//使用mapper接口类路径
<mapper class="cn.test.mybatis.mapper.UserMapper"/>
//注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=""/>
//注册指定包下的所有mapper接口
<package name="cn.test.mybatis.mapper"/>
//注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
如果输入类型时vo包装类
#{}中应该填写包装类中属性对象中的属性
如
#{user.name}
输出resultMap(输出类型)
用于查询字段和pojo属性名不一致,用resultMap手动映射
<resultMap type="Orders" id="orders">
<id colunm="数据库表字段" property="pojo属性"/> //id映射
<result column="数据库表字段" property="pojo属性"/> //其他字段映射
//单表时,可以只手动映射名字不一样的字段
</resultMap>
<select id="selectOrdersList" resultMap="roders">
select id,user_id,number from orders
</select>
动态sql
通过mybatis提供的各种标签实现动态拼接sql
<select id="selectUserBySexAndUsername" parameterType="user" resultType="User">
select * from user
<where>
<if test="sex!=null and sex!=''">
sex = #{sex}
</if>
<if test="username !=null and username !=''">
AND username LIKE
'%${username}%'
</if>
</select>
where标签可以去除第一个and
防止sql出现AND username LIKE..的情况
sql片段
多次出现的重复部分,提取共用
<sql id="selector">
select * from user
</sql>
<include refid="selector"/>
foreach
向sql传递数组或List,mybatis使用foreach解析
QueryVo
<!-- 根据ids查询用户 -->
<select id="queryUserByIds" parameterType="queryVo" resultType="user">
SELECT * FROM `user`
<where>
<!-- foreach标签,进行遍历 -->
<!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
<!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
<!-- open:在前面添加的sql片段 -->
<!-- close:在结尾处添加的sql片段 -->
<!-- separator:指定遍历的元素之间使用的分隔符 -->
<foreach collection="ids" item="item" open="id IN (" close=")"
separator=",">
#{item}
</foreach>
</where>
</select>
测试
// 使用userMapper执行根据条件查询用户
QueryVo queryVo = new QueryVo();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(10);
ids.add(24);
queryVo.setIds(ids);
List<User> list = userMapper.queryUserByIds(queryVo);
遍历数组
<where>
<include refid=" ">
<where>
<foreach collection="Array" ...>
//list只需将Array换成List
<foreach collection="List" ...>
多表关联查询
一对一查询
可以使用resultType或者resultMap
resultType需要在pojo类中加上所需要的字段
resultMap加入所需要的对象属性
resultMap
如 在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。
<resultMap type="order" id="orderUserResultMap">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
<!-- association :配置一对一属性 -->
<!-- property:order里面的User属性名 -->
<!-- javaType:属性类型 -->
<association property="user" javaType="user">
<!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
</association>
</resultMap>
<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`order` o
LEFT JOIN `user` u ON o.user_id = u.id
</select>
测试
// 使用userMapper执行根据条件查询用户
List<Order> list = userMapper.queryOrderUserResultMap();
一对一查询时,resultMap中配置的映射不能省略,否则会映射不到
一对多查询
案例:查询所有用户信息及用户关联的订单信息。
用户信息和订单信息为一对多关系。
在User类中加入List orders属性
<resultMap type="user" id="userOrderResultMap">
<id property="id" column="id" />
<result property="username" column="username" />
<result property="birthday" column="birthday" />
<result property="sex" column="sex" />
<result property="address" column="address" />
<!-- 配置一对多的关系 -->
<collection property="orders" javaType="list" ofType="order">
<!-- 配置主键,是关联Order的唯一标识 -->
<id property="id" column="oid" />
<result property="number" column="number" />
<result property="createtime" column="createtime" />
<result property="note" column="note" />
</collection>
</resultMap>
<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address,
o.id oid,
o.number,
o.createtime,
o.note
FROM
`user` u
LEFT JOIN `order` o ON u.id = o.user_id
</select>
测试
// 使用userMapper执行根据条件查询用户
List<User> list = userMapper.queryUserOrder();