JavaWeb笔记017 Mybatis动态DAO,以及一些坑

上一篇博文中介绍的是Mybatis的基本使用,手动加载调用xml中的mapper。本篇介绍一下动态DAO,不需要手动去调用xml中的SQL。

SQL语句配置文件和DAO编写
DAO

public interface UserMapper {

	public User findUserById(Integer id);
	
	//动态代理形势中,如果返回结果集问List,那么mybatis会在生成实现类的使用会自动调用selectList方法
	public List<User> findUserByUserName(String userName);
	
	public void insertUser(User user);
	
	// 加了@Param xml中的语句使用对象中的参数时,一级参数名也必须加上前缀,例如user.name而不能直接写name
	// public void insertUser(@org.apache.ibatis.annotations.Param("user") User user);
	
	public List<User> findUserbyVo(QueryVo vo);
	
	public List<User> findUserByUserNameAndSex(User user);
	
	public List<User> findUserByIds(QueryVo vo);
	
	public List<CustomOrders> findOrdersAndUser1() ;
	
	public List<Orders> findOrdersAndUser2();
	
	public List<User> findUserAndOrders();
}
// 查询VO对象
public class QueryVo {

	private User user;
	
	private List<Integer> ids;

    ...
}


<?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">
<!-- 
mapper接口代理实现编写规则:
    0. 配置文件文件名和DAO文件名要相同,在同一个目录下,方便引用
	1. 映射文件中namespace要等于接口的全路径名称
	2. 映射文件中sql语句id要等于接口的方法名称:配置文件中的三条SQL语句的id和上面DAO的方法名是相同的
	3. 映射文件中传入参数类型要等于接口方法的传入参数类型
	4. 映射文件中返回结果集类型要等于接口方法的返回值类型
 -->
<mapper namespace="cn.mapper.UserMapper"><!--这里是规则1,namespace要等于接口的全路径名称-->

	<!-- 
	id:sql语句唯一标识
	parameterType:指定传入参数类型
	resultType:返回结果集类型
	#{}占位符:起到占位作用,如果传入的是基本类型(string,long,double,int,boolean,float等),那么#{}中的变量名称可以随意写.
	 -->
	<select id="findUserById" parameterType="int" resultType="cn.pojo.User">
		select * from user where id=#{id}
	</select>
	
	<!-- 
	如果返回结果为集合,可以调用selectList方法,这个方法返回的结果就是一个集合,所以映射文件中应该配置成集合泛型的类型
	${}拼接符:字符串原样拼接,如果传入的参数是基本类型(string,long,double,int,boolean,float等),那么${}中的变量名称必须是value
	注意:拼接符有sql注入的风险,所以慎重使用
	 -->
	<select id="findUserByUserName" parameterType="string" resultType="user"><!--注意这里,需要核心配置文件配合配置,一般我们直接写类的全路径即可-->
		select * from user where username like '%${value}%'
	</select>
	
	<!-- 
	#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性.....
	如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
	 -->
	<insert id="insertUser" parameterType="cn.pojo.User" >
		<!-- 执行 select LAST_INSERT_ID()数据库函数,返回自增的主键
		keyProperty:将返回的主键放入传入参数的Id中保存.
		order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER
		resultType:id的类型,也就是keyproperties中属性的类型
		-->
		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
			select LAST_INSERT_ID()
		</selectKey>
		insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
	</insert>
	
	<select id="findUserbyVo" parameterType="cn.pojo.QueryVo" resultType="cn.pojo.User">
		select * from user where username like '%${user.username}%' and sex=#{user.sex}
	</select>
	
	<!-- 封装sql条件,封装后可以重用. 
	id:是这个sql条件的唯一标识 -->
	<sql id="user_Where">
		<!-- where标签作用:
				会自动向sql语句中添加where关键字
				会去掉第一个条件的and关键字
			 -->
		<where>
			<if test="username != null and username != ''">
				and username like '%${username}%'
			</if>
			<if test="sex != null and sex != ''">
				and sex=#{sex}
			</if>
		</where>
	</sql>
	
	<select id="findUserByUserNameAndSex" parameterType="cn.pojo.User" resultType="cn.pojo.User">
		select * from user 
		
		<!-- 调用sql条件 -->
		<include refid="user_Where"></include>
	</select>
	
	<select id="findUserByIds" parameterType="cn.pojo.QueryVo" resultType="cn.pojo.User">
		select * from user
		
		select * from user
		<where>
			<if test="ids != null">
				<!-- 
				foreach:循环传入的集合参数
				collection:传入的集合的变量名称
				item:每次循环将循环出的数据放入这个变量中
				open:循环开始拼接的字符串
				close:循环结束拼接的字符串
				separator:循环中拼接的分隔符
				 -->
				<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
					#{id}
				</foreach>
			</if>
		</where>
	</select>
	
	<!-- 一对一:自动映射 -->
	<select id="findOrdersAndUser1" resultType="cn.pojo.CustomOrders"><!--创建一个CustomOrders类,里面的属性和联合查询出来的字段一一对应即可-->
		select a.*, b.id uid, username, birthday, sex, address 
		from orders a, user b 
		where a.user_id = b.id
	</select>
	
	<!-- 一对一:手动映射 -->
	<!-- 
	id:resultMap的唯一标识
	type:将查询出的数据放入这个指定的对象中
	注意:手动映射需要指定数据库中表的字段名与java中pojo类的属性名称的对应关系
	Orders类中的属性可以是基本类型和类的组合,例如有个User类型的属性
	 -->
	<resultMap type="cn.pojo.Orders" id="orderAndUserResultMap">
		<!-- id标签指定主键字段对应关系
		column:列,数据库中的字段名称
		property:属性,java中pojo中的属性名称
		 -->
		<id column="id" property="id"/>
		
		<!-- result:标签指定非主键字段的对应关系 -->
		<result column="user_id" property="userId"/>
		<result column="number" property="number"/>
		<result column="createtime" property="createtime"/>
		<result column="note" property="note"/>
		
		<!-- 这个标签指定单个对象的对应关系 
		property:指定将数据放入Orders中的user属性中
		javaType:user属性的类型
		-->
		<association property="user" javaType="cn.pojo.User">
			<id column="uid" property="id"/>
			<result column="username" property="username"/>
			<result column="birthday" property="birthday"/>
			<result column="sex" property="sex"/>
			<result column="address" property="address"/>
		</association>
	</resultMap>
	<select id="findOrdersAndUser2" resultMap="orderAndUserResultMap">
		select a.*, b.id, b.uid, b.username, b.birthday, b.sex, b.address 
		from orders a, user b 
		where a.user_id = b.id
	</select>
	
	<resultMap type="cn.pojo.User" id="userAndOrdersResultMap">
		<id column="id" property="id"/>
		<result column="username" property="username"/>
		<result column="birthday" property="birthday"/>
		<result column="sex" property="sex"/>
		<result column="address" property="address"/>
		
		<!-- 指定对应的集合对象关系映射
		property:将数据放入User对象中的ordersList属性中
		ofType:指定ordersList属性的泛型类型
		注意这里!!!!集合中的主键字段名字不能喝user对象中的主键相同,例如都叫id,则会只能查出来1条
		 -->
		<collection property="ordersList" ofType="cn.pojo.Orders">
			<id column="oid" property="id"/>
			<result column="user_id" property="userId"/>
			<result column="number" property="number"/>
			<result column="createtime" property="createtime"/>
		</collection>
	</resultMap>
	<select id="findUserAndOrders" resultMap="userAndOrdersResultMap">
		select a.*, b.id oid ,user_id, number, createtime 
		from user a, orders b where a.id = b.user_id
	</select>
</mapper>




补充,如果参数是map,如何遍历?
	<select id="queryAdSlotKVByCondition" resultType="com.dhgate.ssp.des.entity.db.AdSlotKVSetting" parameterType="java.util.Map">
		SELECT * FROM
		dh_ssp.adslotkvsetting
		<if test="condition != null">
			WHERE
			<foreach collection="condition.keys" separator=" and " item="key">
				${key}=#{condition[${key}]}
			</foreach>
		</if>
	</select>
foreach循环中会拼接成key1=value1 and key2=value2...这种形式

核心配置文件

db.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=admin

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="db.properties"></properties>
	
	<typeAliases> 
		<!-- 定义单个pojo类别名,例如上面SQL语句配置文件中使用的User类
		type:类的全路劲名称
		alias:别名
		 -->
<!-- 		<typeAlias type="cn.pojo.User" alias="user"/> -->
		
		<!-- 使用包扫描的方式批量定义别名 
		定以后别名等于类名,不区分大小写,但是建议按照java命名规则来,首字母小写,以后每个单词的首字母大写
		-->
		<package name="cn.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.url}" />
			<property name="username" value="${jdbc.username}" />
			<property name="password" value="${jdbc.password}" />
		</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper resource="User.xml"/>
		
		<!-- 
		使用class属性引入接口的全路径名称:
		使用规则:
			1. 接口的名称和映射文件名称除扩展名外要完全相同
			2. 接口和映射文件要放在同一个目录下
		 -->
<!-- 		<mapper class="cn.mapper.UserMapper"/> -->
		
		<!-- 使用包扫描的方式批量引入Mapper接口 
				使用规则:
				1. 接口的名称和映射文件名称除扩展名外要完全相同
				2. 接口和映射文件要放在同一个目录下
		-->
		<package name="cn.mapper"/>
	</mappers>
</configuration>

代码调用
public class UserMapperTest {
	private SqlSessionFactory factory;
	
	//作用:在测试方法前执行这个方法
	@Before
	public void setUp() throws Exception{
		String resource = "SqlMapConfig.xml";
		//通过流将核心配置文件读取进来
		InputStream inputStream = Resources.getResourceAsStream(resource);
		//通过核心配置文件输入流来创建会话工厂
		factory = new SqlSessionFactoryBuilder().build(inputStream);
	}
	
	@Test
	public void testFindUserById() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		User user = mapper.findUserById(1);
		System.out.println(user);
	}
	
	@Test
	public void testFindUserByUserName() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		List<User> list = mapper.findUserByUserName("王");
		
		System.out.println(list);
	}
	
	@Test
	public void testInsertUser() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		User user = new User();
		user.setUsername("老王");
		user.setSex("1");
		user.setBirthday(new Date());
		user.setAddress("北京昌平");
		
		mapper.insertUser(user);
		
		openSession.commit();
	}
	
	@Test
	public void testFindUserByVo() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		QueryVo vo = new QueryVo();
		User user = new User();
		user.setUsername("王");
		user.setSex("1");
		vo.setUser(user);
		
		List<User> list = mapper.findUserbyVo(vo);
		System.out.println(list);
		
	}
	
	@Test
	public void testFindUserbyUserNameAndSex() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		User user = new User();
		user.setUsername("王");
		user.setSex("1");
		
		List<User> list = mapper.findUserByUserNameAndSex(user);
		
		System.out.println(list);
	}
	
	@Test
	public void testFindUserbyIds() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		QueryVo vo = new QueryVo();
		List<Integer> ids = new ArrayList<Integer>();
		ids.add(1);
		ids.add(16);
		ids.add(28);
		ids.add(22);
		vo.setIds(ids);
		
		List<User> list = mapper.findUserByIds(vo);
		System.out.println(list);
	}
	
	@Test
	public void testFindOrdersAndUser() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		List<CustomOrders> list = mapper.findOrdersAndUser1();
		System.out.println(list);
	}
	
	@Test
	public void testFindOrdersAnduUser2() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		List<Orders> list = mapper.findOrdersAndUser2();
		System.out.println(list);
	}
	
	@Test
	public void testFindUserAndOrders() throws Exception{
		SqlSession openSession = factory.openSession();
		//通过getMapper方法来实例化接口
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		
		List<User> list = mapper.findUserAndOrders();
		System.out.println(list);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值