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>
@Testpublic 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>
@Testpublic 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 userwhere 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>
@Testpublic 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>
@Testpublic 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 userwhere id in<foreach collection="ids" item="item" separator="," open="(" close=")">#{item}</foreach></select>
@Testpublic 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);
<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_idWHERE o.order_number=#{orderNumber}</select>
@Testpublic 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 orderNumberFROM tb_user u INNER JOIN tb_order o ON u.id=o.user_idWHERE u.id=#{id}</select>
@Testpublic 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);
@Testpublic 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();}