MyBatis
- MyBtias工具类
- 参数
- 入参
- 参数是单个参数
- 参数是多个参数
- 入参是POJO对象
- 入参是Map类型
- 自动主键增长
- #{}和${}两种获取参数方式
- 结果映射
- 动态SQL
- MyBatis多表查询
- MyBatis注解开发
MyBtias工具类
- SessionUtils.java
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
public class SessionUtils {
static SqlSessionFactory factory=null;
//在静态代码块创建会话工厂对象
static {
try {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
//定义静态方法获取会话对象,自动提交事务
public static SqlSession getSqlSession(){
SqlSession session = factory.openSession(true);
//返回给调用者会话对象
return session;
}
//定义静态方法获取会话对象,方法调用者传递参数决定是否提交事务
public static SqlSession getSqlSession(boolean isAutoCommit){
SqlSession session = factory.openSession(isAutoCommit);
//返回给调用者会话对象
return session;
}
//接受会话对象,手动提交事务关闭会话对象
public static void commitAndClose(SqlSession session){
//判断session是否为空
if(session!=null){
//手动提交事务
session.close();
//关闭会话对象
session.close();
}
}
//接受会话对象,回滚事务关闭会话
public static void rollbackAndClose(SqlSession session){
//判断session是否为空
if(session!=null){
//回滚事务
session.rollback();
//关闭会话对象
session.close();
}
}
}
参数
输入参数 | 输出参数 |
---|---|
HashMap | HashMap |
String、Integer | String、Integer |
POJO | POJO |
入参
参数是单个参数
/**
* 查询单个用户ID
* @param id
* @return
*/
User queryById(Integer id);
<select id="queryById" resultType="user">
select * from user where id=#{id}
</select>
使用#{任意标识符},但是一般见名知意。
参数是多个参数
方式1:使用参数的索引获取arg0 arg1(舍弃,一般不用)
/**
* 根据用户名和性别查询用户
* @param userName
* @param sex
* @return
*/
User queryByUserNameAndSex(String userName,String sex);
<select id="queryByUserNameAndSex" resultType="user">
select * from user where user_name=#{arg0} and sex=#{arg1}
</select>
方式2:使用参数的位置获取param0 param1(舍弃,一般不用)
/**
* 根据用户名和性别查询用户
* @param userName
* @param sex
* @return
*/
User queryByUserNameAndSex(String userName,String sex);
<select id="queryByUserNameAndSex" resultType="user">
select * from user where user_name=#{param1} and sex=#{param2}
</select>
方式3:使用@Param注解(重点掌握)
/**
* 根据用户名和性别查询用户
* @param userName
* @param sex
* @return
*/
User queryByUserNameAndSex(@Param(value = "userName") String userName,
@Param(value = "sex") String sex);
<select id="queryByUserNameAndSex" resultType="user">
select * from user where user_name=#{userName} and sex=#{sex}
</select>
入参是POJO对象
接口方法传入pojo类型的数据时,xml中使用#{pojo属性名称}可直接获取传入对象对应的属性值
/**
* 添加=用户
* @param user
* @return
*/
void addUser(User user);
<insert id="addUser">
insert into user value (null,#{userName},#{birthday},#{sex},#{address})
</insert>
入参是Map类型
接口方法传入Map类型的数据时,xml中使用#{map中key}可直接获取map中的value值
/**
* 根据性别和地址查询用户
* @param map
* @return
*/
List<User> querySexAndAddress(Map<String, String> map);
<select id="querySexAndAddress" resultType="user">
select * from user where sex=#{sex} and address=#{address}
</select>
@Test
public void test2() throws Exception {
SqlSession sqlSession = SessionUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,String> map=new HashMap<>();
map.put("sex","男");
map.put("address","河南");
List<User> users = mapper.querySexAndAddress(map);
users.forEach(u-> System.out.println(u));
sqlSession.close();
}
自动主键增长
新增一条数据,主键自动增长,查询主键值
使用insert标签的属性useGeneratedKeys,keyProperty,keyColumn实现;
属性 | 说明 |
---|---|
useGeneratedKeys | true 获取自动生成的主键,相当于select last_insert_id() |
keyColumn | 表中主键的列名 |
keyProperty | 实体类中主键的属性名 |
<insert id="addUser2" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into user value (null,#{userName},#{birthday},#{sex},#{address})
</insert>
#{}和${}两种获取参数方式
1.使用#{}的sql是进行预编译的,可以防止sql注入;
2.
$ {id} 获取id值时,必须使用命名参数取值@param;
如果是取单个值,也可使用${value}获取;
参数值直接拼接到sql中,会有sql注入的风险;
结果映射
mybatis框架提供了resultType和resultMap
resultType返回值
① 返回值是基本数据类型,int string
②返回值是POJO对象,返回POJO对象的全限定名
③返回值是List POJO对象时,返回POJO对象的全限定名
④返回值是Map对象时,返回map
⑤返回值是多个Map对象时,使用注解@MapKey(指定字段名称)
@MapKey("id")
Map<Integer,User> getUsers();
resultMap主要解决数据库字段名称与POJO类属性名称不一致
完成高级查询,比如一对一 一对多 多对多
<resultMap id="u" type="user">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
</resultMap>
<select id="getUsers2" resultMap="u">
select * from user where id=1
</select>
动态SQL
if:判断条件
choose when otherwise:分支判断
where标签
set标签
foreach标签
if标签:
<if test="判断条件">
sql语句块
</if>
如果判断条件为true,执行sql语句块,否则不执行
/**
* 查询所有男性,如果输入用户名模糊查询,否则只查询男性
*/
List<User> queryMale(@Param(value = "userName")String userName);
<select id="queryMale" resultType="user">
select * from user
where sex='男'
<if test="userName!=null and userName.trim()!=''">
and user_name like concat('%',#{userName},'%')
</if>
</select>
@Test
public void test() throws Exception {
SqlSession sqlSession = SessionUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.queryMale(null);
users.forEach(u-> System.out.println(u));
sqlSession.close();
}
choose when otherwise:分支选择
when test条件满足执行语句,若条件都不满足,执行otherwise
/**
* 编写一个查询方法,设置两个参数,一个是用户名,一个是住址。
* 根据用户名或者住址查询所有男性用户:
* 如果输入了用户名则按照用户名模糊查找,
* 否则就按照住址查找,两个条件只能成立一个,
* 如果都不输入就查找用户名为“孙悟空”的用户。
*/
List<User> queryChoose(@Param(value = "userName") String userName,
@Param(value = "address") String address);
<select id="queryChoose" resultType="user">
select * from user
where sex='男'
<choose>
<when test="userName !=null and userName.trim()!=''">
and user_name like concat('%',#{userName},'%')
</when>
<when test="address !=null and address.trim()!=''">
and address=#{address}
</when>
<otherwise>
and user_name='孙悟空'
</otherwise>
</choose>
</select>
@Test
public void test2() throws Exception {
SqlSession sqlSession = SessionUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.queryChoose(null, "开封");
users.forEach(u-> System.out.println(u));
sqlSession.close();
}
where标签
加where关键字
被where标签包裹的sql会自动去除多余的and或者or关键字
/**
* 如果只输入了用户名按照用户名进行查询;
* select * from user where user_name like concat('%',#{userName},'%');
* 如果只输入住址,按住址进行查询
* select * from user where address=#{address};
* 如果两者都输入,则按照两个条件查询
* select * from user where user_name like concat('%',#{userName},'%') and address=#{address};
* 如果两者都不合符条件,全表查询;
* select * from user
*/
List<User> queryWhere(@Param(value = "userName") String userName,
@Param(value = "address") String address);
<select id="queryWhere" resultType="user">
select * from user
<where>
<if test="userName !=null and userName.trim()!=''">
user_name like concat('%',#{userName},'%')
</if>
<if test="address !=null and address.trim()!=''">
and address=#{address}
</if>
</where>
</select>
set标签
加set关键字
去除最后多余的逗号
/**
* 修改用户信息 如果某个属性为null,则不修改
*/
void updateSet(User user);
<update id="updateSet">
update user
<set>
<if test="userName!=null">
user_name=#{userName},
</if>
<if test="birthday !=null">
birthday=#{birthday},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
<if test="address!=null">
address=#{address},
</if>
</set>
where id=#{id}
</update>
@Test
public void test3() throws Exception {
SqlSession sqlSession = SessionUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User u=new User();
u.setUsername("杨民民");
u.setBirthday(new Date());
u.setSex("女");
u.setAddress(null);
u.setId(8);
mapper.updateSet(u);
sqlSession.close();
}
foreach:遍历集合或数组
collection属性:接收的集合或者数组,集合名或者数组名
item属性:集合或者数组参数中的每一个元素
separator属性:标签分隔符
open属性:以什么开始
close以什么结束
/**
* 按照id值是1、2、3来查询用户
*/
List<User> findByIds(@Param("ids") List<Integer> ids);
<select id="findByIds" resultType="user">
select * from user
where id in
<foreach collection="ids" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</select>
@Test
public void test4() throws Exception {
SqlSession sqlSession = SessionUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<Integer> ls=new ArrayList<>();
Collections.addAll(ls,1,2,3);
List<User> byIds = mapper.findByIds(ls);
byIds.forEach(u-> System.out.println(u));
sqlSession.close();
}
MyBatis多表查询
表与表的关系:一对一,一对多,多对多
数据库环境准备:
DROP TABLE IF EXISTS `tb_item`;
CREATE TABLE `tb_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_name` varchar(32) NOT NULL COMMENT '商品名称',
`item_price` float(6,1) NOT NULL COMMENT '商品价格',
`item_detail` text COMMENT '商品描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_item
-- ----------------------------
INSERT INTO `tb_item` VALUES ('1', 'iPhone 6', '5288.0', '苹果公司新发布的手机产品。');
INSERT INTO `tb_item` VALUES ('2', 'iPhone 6 plus', '6288.0', '苹果公司发布的新大屏手机。');
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_name` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
`age` int(10) DEFAULT NULL COMMENT '年龄',
`sex` int(11) DEFAULT NULL COMMENT '0-女 1-男',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES ('1', 'zhangsan', '123456', '张三', '30', '1');
INSERT INTO `tb_user` VALUES ('2', 'lisi', '123456', '李四', '21', '0');
INSERT INTO `tb_user` VALUES ('3', 'wangwu', '123456', '王五', '22', '1');
INSERT INTO `tb_user` VALUES ('4', 'zhangwei', '123456', '张伟', '20', '1');
INSERT INTO `tb_user` VALUES ('5', 'lina', '123456', '李娜', '28', '0');
INSERT INTO `tb_user` VALUES ('6', '蔡徐坤', '123', '小菜', '18', '1');
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`order_number` varchar(20) NOT NULL COMMENT '订单号',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_1` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_order
-- ----------------------------
INSERT INTO `tb_order` VALUES ('1', '1', '20140921001');
INSERT INTO `tb_order` VALUES ('2', '2', '20140921002');
INSERT INTO `tb_order` VALUES ('3', '1', '20140921003');
DROP TABLE IF EXISTS `tb_orderdetail`;
CREATE TABLE `tb_orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(32) DEFAULT NULL COMMENT '订单号',
`item_id` int(32) DEFAULT NULL COMMENT '商品id',
`total_price` double(20,0) DEFAULT NULL COMMENT '商品总价',
`status` int(11) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`order_id`),
KEY `FK_orderdetail_2` (`item_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`order_id`) REFERENCES `tb_order` (`id`),
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`item_id`) REFERENCES `tb_item` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_orderdetail
-- ----------------------------
INSERT INTO `tb_orderdetail` VALUES ('1', '1', '1', '5288', '1');
INSERT INTO `tb_orderdetail` VALUES ('2', '1', '2', '6288', '1');
INSERT INTO `tb_orderdetail` VALUES ('3', '2', '2', '6288', '1');
INSERT INTO `tb_orderdetail` VALUES ('4', '3', '1', '5288', '1');
一对一查询
resultMap标签中子标签association实现一对一查询
通过订单编号20140921003查询出订单信息,并查询出下单人信息。
说明:一个订单只能对应一个用户信息;
/**
* 根据订单号查询下单人信息
* @param orderNumber
* @return
*/
Order findOrderByNumber(@Param("orderNumber")String orderNumber);
<!--
实现一对一查询
1.resultMap标签实现多表查询
2.通过id="queryOneToOneResultMap"的属性值关联下面的sql语句,和下面select标签的resultMap="queryOneToOneResultMap"属性值一致
3.type="Order" : 表示接口方法 Order queryOneToOne(@Param("orderNumber") String orderNumber);返回值类型
4.多表查询一定书写autoMapping="true"
-->
<resultMap id="queryOneToOneResultMap" type="Order" autoMapping="true">
<id column="id" property="id"></id>
<result column="order_number" property="orderNumber"></result>
<association property="user" javaType="User" autoMapping="true">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
</association>
</resultMap>
<select id="findOrderByNumber" resultMap="queryOneToOneResultMap">
SELECT *
FROM tb_user u INNER JOIN tb_order o ON u.id=o.user_id
WHERE o.order_number=#{orderNumber}
</select>
@Test
public void test1(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
Order orderByNumber = mapper.findOrderByNumber("20140921003");
System.out.println(orderByNumber);
sqlSession.close();
}
一对多查询
resultMap标签中子标签collection实现一对多查询
property 映射的类中属性名称
javaType list
ofType 集合泛型
查询id为1的用户及其订单信息
/**
* 查询id为1的用户及其订单信息
* id=1的用户只要1个
* 订单表中用户id的订单可能有多个
*/
User findOrdersById(@Param("id")Integer id);
<resultMap id="queryOneToSomeResultMap" type="User" autoMapping="true">
<id column="id" property="id"></id>
<collection property="orderList" javaType="List" ofType="Order" autoMapping="true">
<id column="oid" property="id"></id>
</collection>
</resultMap>
<select id="findOrdersById" resultMap="queryOneToSomeResultMap">
SELECT u.*,o.id AS oid,o.order_number AS orderNumber
FROM tb_user u INNER JOIN tb_order o ON u.id=o.user_id
WHERE u.id=#{id}
</select>
@Test
public void test2(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession(false);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.findOrdersById(1);
System.out.println(user);
sqlSession.close();
}
MyBatis注解开发
@Select查询
@Insert新增
@Update修改
@Delete删除
@Options 可选配置(主键回填)
这里只举例@Insert注解,其它注解类似。
//定义方法实现注解插入数据到tb_user表中
/*
#{userName} : 因为addUser方法的形参类型是复杂类型pojo即User实体类,所以这里大括号中书写的内容userName看User实体类中的成员变量userName
或者User实体类中的getUserName() 去掉get将U变为u即userName
*/
@Insert("insert into tb_user values (null,#{userName},#{password},#{name},#{age},#{sex})")
void addUser(User user);
@Test
public void addUser(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=new User();
user.setUserName("hhh");
user.setPassword("123456");
user.setName("哈哈哈");
user.setAge(1);
user.setSex(0);
mapper.addUser(user);
sqlSession.close();
}