mybatis(四)开发dao方法 开发原始dao方法 mapper代理开发方法

mybatis开发dao方法

 

1. SqlSession在代码中的使用场合

使用场合:sqlSession在使用时由SqlSessionFactory生成创建一个Sqlsession会话对象,对象在代码中可以定义为成员变量、方法形参、方法的局部变量。

 

 

2. SqlSessionFactory

SqlSessionFactory作为会话工厂,创建sqlSession,可以将SqlSessionFactory以单例方式。

 

3. SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFactory,又由于SqlSessionFactory以单例方式,可以将SqlSessionFactoryBuilder简单的当成一个工具类来使用即可。

 

 

1.1.2 SqlSession

sqlSession是一个面向程序员接口。

SqlSession作用是操作数据库,sqlSession对象要存储数据库连接、事务、一级缓存结构等。

sqlSession对象是线程不安全的(多线程访问系统,当多线程同时使用一个sqlsession对象时会造成数据冲突问题)

 

由于sqlSession对象是线程不安全的,sqlSession最佳使用场合在方法体内作为局部变量来使用


 1.开发原始dao方法

   Used.xml映射文件



dao接口和dao实现类

需要编写dao接口及dao实现类。

package com.mybatis.demo_01.dao;

import java.util.List;

import com.mybatis.demo_01.pojo.User;

public interface UserDao {
	
	/**
	 * 用户管理的dao
	 * 
	 */
	
	// 根据用户id查询用户信息
	public User findUserById(int id)throws Exception;
	
	//根据用户名称模糊查询
	public List<User> findUserByName()throws Exception;
	
	//添加用户
	public void insertUser(User user)throws Exception;

}

package com.mybatis.demo_01.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.mybatis.demo_01.pojo.User;

public class UserDaoImpl implements UserDao {

	// 接口实现类中注入SqlSessionFactory
	private SqlSessionFactory sessionFactory;

	// 通过构造方法注入
	public UserDaoImpl(SqlSessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	@Override
	public User findUserById(int id) throws Exception {

		// sqlSeesion定义为局部变量使用
		SqlSession sqlSession = sessionFactory.openSession();

		User user = sqlSession.selectOne("test.findUserbyId", 28);

		// 关闭会话
		sqlSession.close();

		return user;
	}

	@Override
	public List<User> findUserByName() throws Exception {

		// sqlSeesion定义为局部变量使用
		SqlSession sqlSession = sessionFactory.openSession();

		List<User> list = sqlSession.selectList("test.findUserByName", "张");

		// 关闭会话
		sqlSession.close();

		return list;
	}

	@Override
	public void insertUser(User user) throws Exception {

		// sqlSeesion定义为局部变量使用
		SqlSession sqlSession = sessionFactory.openSession();

		sqlSession.insert("test.insertUser", user);
		
		sqlSession.commit();

		// 关闭会话
		sqlSession.close();

	}

}

测试
package com.mybatis.demo_01.dao;

import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import com.mybatis.demo_01.pojo.User;

public class UserDaoImplTest {

	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void setUp() throws Exception {
		// 删除用户信息

		// 配置文件
		String resource = "SqlMapConfig.xml";

		InputStream inputStream = Resources.getResourceAsStream(resource);

		// 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
		 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

	}

	@Test
	public void testFindUserById() throws Exception {
		
		UserDao userDaoImpl = new UserDaoImpl(sqlSessionFactory);
		
		User user = userDaoImpl.findUserById(5);
		
		System.out.println(user);

	}
	
	
	@Test
	public void testFindUserByName() throws Exception {
		
		UserDao userDaoImpl = new UserDaoImpl(sqlSessionFactory);
		
		List<User> user = userDaoImpl.findUserByName();
		
		for (User u : user) {			
			System.out.println(u);
		}		
	}
}

 存在问题 

1dao接口实现类方法中存在大量的重复代码,这些重复的代码就是模板代码。

模板代码:

先创建sqlsession

再调用sqlsession的方法

再提交sqlsession

再关闭sqlsession

 

2、在调用sqlSession的方法时存在硬编码

调用sqlsession方法第一个参数是 statement id就是硬编码。


 mapper代理开发方法

  只需要编写dao接口(即mapper接口),由mybatis 框架自动生成接口实现的代理对象

 

1. 分析

mapper代理方法要生成一个代理对象,代理对象内部执行的方法内容类似原始dao开发的dao实现类。

mapper代理类方法主要是对调用sqlsession的方法进行封装,如下:

sqlSession.selectOne("test.findUserById", id)

sqlSession.selectList("test.findUserByName", "")

sqlSession.insert("test.insertUser", user);

 

对以上代码进行哪些封装?

什么时候调用sqlSession 的selectOne方法、什么时候调用sqlSession 的selecList方法,什么时候 调用insert。。。。

解决方法:可以根据映射文件中标签类型一决定是执行select方法还是执行insert方法等。。

 

硬编码的statementid如何封装。

解决方法:要解决映射文件中statementmapper接口的方法的对应关系,在生成的代理对象方法中就知道该 代理对象的方法对应去调用哪个映射文件中statement


2.开发规范

mybatis要解决映射文件中statementmapper接口的方法对应起来。 

可以遵循一个开发规范让statementmapper接口的方法对应起来:

 

1、映射文件和mapper接口类的对应

映射文件中namespace等于mapper接口类路径

<?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配置文件是SQL文件为单位进行配置的,最终将封装到mappedStatement对象中 
		namespace的作用是对SQL语句进行更好的隔离,方便管理
		
注意:后面讲mapper代理的开发方式namespace有特殊的作用:
		namespace等于接口类路径,这样通过映射文件找到对应的mapper接口是哪个
->
<mapper namespace="com.mybatis.demo_01.mapper.UserMapper">

2statementmapper接口的方法对应

将映射文件中statementidmapper中方法名一致

 mapper.java
package com.mybatis.demo_01.mapper;

import java.util.List;

import com.mybatis.demo_01.pojo.User;

public interface UserMapper {
	
	/**
	 * 用户管理的dao
	 * 
	 */
	
	// 根据用户id查询用户信息
	public User findUserbyId(int id)throws Exception;
	
	//查询用户使用resultMap
	public User findUserbyIdResultMap(int id) throws Exception;
	
	//根据用户名称模糊查询
	public List<User> findUserByName()throws Exception;
	
	//添加用户
	public void insertUser(User user)throws Exception;

}
mapper.xml
<?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配置文件是SQL文件为单位进行配置的,最终将封装到mappedStatement对象中 
		namespace的作用是对SQL语句进行更好的隔离,方便管理
		
注意:后面讲mapper代理的开发方式namespace有特殊的作用:

		namespace等于接口类路径,这样通过映射文件找到对应的mapper接口是哪个
-->
<mapper namespace="com.mybatis.demo_01.mapper.UserMapper">

<!-- 打开二级缓存 -->
<cache/>

	<!-- 根据id获取用户信息
		id用来标识namespace下的SQL语句  将id可以称为statement的id
		select用于查询	主要用于查询,输入参数类型,输出参数类型   最终select语句就会封装到mapper语句的对象中,
				可以将select语句称为statement
				
		#{}:表示一个占位符   可以防止SQL注入
		#{value}:value表示接受参数输入参数的值,如果接受的参数是简单数据类型,#{}里面可以写value或者其他的名称
		
		resultType:将SQL查询的结果集映射成为Java对象
		将多个列的值映射到一个Java对象中,需要自定义一个pojo(模型数据),映射的规则就是SQL查询列名和pojo的属性名必须一直可完成映射
		resultType:指定的单条记录所映射的Java对象
		

3、让mapper的接口方法的输入参数类型和statementparameterType指定的参数类型保持一致

4、让mapper的接口方法返回值类型和statementresultType指定的类型保持一致。

-->

<?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配置文件是SQL文件为单位进行配置的,最终将封装到mappedStatement对象中 
		namespace的作用是对SQL语句进行更好的隔离,方便管理
		
注意:后面讲mapper代理的开发方式namespace有特殊的作用:

		namespace等于接口类路径,这样通过映射文件找到对应的mapper接口是哪个


-->
<mapper namespace="com.mybatis.demo_01.mapper.UserMapper">


<!-- 打开二级缓存 -->
<cache/>


	<!-- 根据id获取用户信息
		id用来标识namespace下的SQL语句  将id可以称为statement的id
		select用于查询	主要用于查询,输入参数类型,输出参数类型   最终select语句就会封装到mapper语句的对象中,
				可以将select语句称为statement
				
		#{}:表示一个占位符   可以防止SQL注入
		#{value}:value表示接受参数输入参数的值,如果接受的参数是简单数据类型,#{}里面可以写value或者其他的名称
		
		resultType:将SQL查询的结果集映射成为Java对象
		将多个列的值映射到一个Java对象中,需要自定义一个pojo(模型数据),映射的规则就是SQL查询列名和pojo的属性名必须一直可完成映射
		resultType:指定的单条记录所映射的Java对象
		
	 -->
	<select id="findUserbyId" parameterType="int" resultType="com.mybatis.demo_01.pojo.User">
	   SELECT id,username,birthday,sex,address FROM user where id =#{value};
	</select>
	
	<!-- 查询用户,使用resultMap完成结果映射   	使用resultMap将列名和pojo的属性值作为一个对应关系,完成映射 
	  id:唯一标识一个元素
	  type:最终映射的pojo类型
	 -->
	
	<resultMap type="user" id="queryUserResultMap">
	
	<!-- id:id标识结果集唯一的标识
	column:结果集中唯一标识的列名
	property:将结果集中唯一标识的列映射到pojo的属性名
	 -->
	<id	column="id_" property="id"/>
	
	<!-- 如果结果集有多个列组合为一个标识,定义两个id标签
		result表示:普通列
		
	 -->
	 
	 <result column="useranme_" property="username"/>
	 <result column="birthday_" property="birthday"/>
	 <result column="sex_" property="sex"/>
	 <result column="address_" property="address"/>

	</resultMap>
	
	<select id="findUserbyIdResultMap" parameterType="int"  resultMap="queryUserResultMap">
	   SELECT id id_,username  useranme_,birthday birthday_,sex sex_,address address_ FROM user where id =#{value};
	</select>
	
	<!-- 根据用户名称模糊查询用户列表信息 
		resultType:不管结果集的数量有多少,resultType指定的单条记录所映射的Java对象
		resultType:映射的规则就是SQL查询的列名和pojo的属性名必须一直方可完成映射
		${}:表示一个字符串的拼接符,相当于字符串的拼接
			SELECT * from user where username LIKE '%  +  ${}  +   %';
		${}:接受参数是一个简单数据类型,${}中只能写value
		${}:拼接是无法防止SQL注入的
	-->
	<select id="findUserByName" parameterType="String" resultType="com.mybatis.demo_01.pojo.User">
	
		SELECT * from user where username LIKE '%${value}%'; 
		
	
	</select>
	
	<!-- 添加用户 
	 
	   输入参数:需要输入参数是多个值,如果传入简单类型是无法满足要求。
	   		输入参数类型可以是pojo类型(包含多个属性)
	   #{}如何获取对象的值呢?   是通过OGNL读取对象的值
	   OGNL的表达式方式:属性.属性.属性.....知道把属性值读取过来为止
	   
	   		
  		mysql数据库通过select  LAST_INSERT_ID();获取自增主键的值,在insert语句执行之后去执行LAST_INSERT_ID()获取新纪录的主键
  		
	
	-->
	
	<insert id="insertUser" parameterType="com.mybatis.demo_01.pojo.User" >
	
	<!-- 
		keyProperty:将主键设置到参数的哪一个属性,设置到user的id属性中
		order:selectKey中的语句在insert语句执行后或前,这里要设置成after
		resultType:select LAST_INSERT_ID()查询出的值类型
	 -->
		<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>
	
	
	<!-- 使用mysql的UUID生成主键 -->
		<insert id="insertUserUUid" parameterType="com.mybatis.demo_01.pojo.User" >
	
	<!-- 
		keyProperty:将主键设置到参数的哪一个属性,设置到user的id属性中
		order:select UUID()在insert语句执行前得到主键,将主键设置到user的属性中
		resultType:select UUID()查询来的值
	 -->
		<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
			select  UUID()
		</selectKey>
		
		insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address});
	
	</insert>

	<!-- 修改用户 -->

   <update id="updateUser" parameterType="com.mybatis.demo_01.pojo.User">
   		update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
   </update>
	<!-- 删除用户 -->
	
	<delete id="deleteUser">
	
		delete from user where id=#{id}
	
	</delete>

</mapper>


mapper.xmlSqlMapConfig.xml加载


 代码实现

package com.mybatis.demo_01.mapper;

import java.io.InputStream;
import java.util.Date;
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 org.junit.Before;
import org.junit.Test;

import com.mybatis.demo_01.pojo.User;

public class UserMapperTest {

	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void setUp() throws Exception {
		// 删除用户信息

		// 配置文件
		String resource = "SqlMapConfig.xml";

		InputStream inputStream = Resources.getResourceAsStream(resource);

		// 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	@Test
	public void testInsertUser() throws Exception {
				
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		
		User user = new User();
		
		user.setUsername("阿斯");
		user.setAddress("迈阿密");
		user.setBirthday(new Date());
		user.setSex("女");
		
		mapper.insertUser(user);
		
		sqlSession.commit();
		sqlSession.close();
	}	
	@Test
	public void testFindUserById() throws Exception {
				
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);			
		
		User user = mapper.findUserbyId(28);
		
		System.out.println(user);
		
		sqlSession.close();

	}
			
	@Test
	public void testFindUserbyIdResultMap() throws Exception {
				
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);			
		
		User user = mapper.findUserbyIdResultMap(28);
		
		System.out.println(user);
		
		sqlSession.close();
	}
}


 selectOneselectList

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

selectOne如果返回多条记录报错:


 namespace

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




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值