mybatis

一、mybatis架构

1、mybatis介绍

mybatis本是apache的一个开源项目iBatis,2010年这个项目由apache software迁移到了google code,并且改名为mybatis,实质上对ibatis进行一些改进。目前mybatis在github上托管。

mybatis是持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,不需要花费精力去处理其他东西。

mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2、mybatis架构

SqlMapConfig.xml:

SqlMapConfig.xml中配置的内容顺序如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

mybatis的全局配置文件,名称不固定,主要配置的是运行环境(数据源、事物),设置全局参数,设置别名

引入数据源外部文件:

    
    

设置全局参数:

设置别名:


	
		
		
		
		
		
	

配置数据库:(和spring整合后不需要了)

    
		
        
      	
        
	      
	        
	        
	        
	        
	      
   	 	
  	

引入mapper.xml文件(该文件主要配置的是sql语句):

    
  		
  	

mapper.xml:

mybatis有两种开发dao的方法:(1)原始开发dao方式(dao接口和dao实现都需要编写)(2)mapper代理方式(只需要写dao接口)

原始开发dao方式

mapper.xml文件编写:



	
    
    
    
	

需要编写dao接口和dao的实现类

dao接口:

public interface UserDao {
	public User findUserById(int id) throws Exception;
}

dao实现类:

public class UserDaoImpl implements UserDao{
	//工厂类
	private SqlSessionFactory sqlSessionFactory;
	
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		super();
		this.sqlSessionFactory = sqlSessionFactory;
	}
	public User findUserById(int id) throws Exception{
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//根据id查询信息
        // 如果查询结果返回的是多条记录,使用selectOne();
		User user = sqlSession.selectOne("test.findUserById", 1);
		sqlSession.close();
		return user;
	}
}

原始开发dao配置文件创建SqlSessionFactory

    private SqlSessionFactory sqlSessionFactory;
	
	@Before
	public void init() throws IOException{
        // 全局配置文件
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建sqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

原始开发dao获取测试

    @Test
	public void testFindUserById(){
		UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        User user = userDao.findUserById(1);
        System.out.println(user);
	}

mapper代理方式:

程序员只需要写dao接口,到接口实现对象由mybatis自动生成代理对象。

原始开发dao方式存在问题:

1、dao的实现类中 存在重复代码,整个mybatis操作的过程代码模块重复(先创建sqlSession、调用sqlsession的方法、关闭sqlsession)

2、dao的实现类中存在硬编码,调用sqlsession方法时将statement的id硬编码。

mapper.xml文件和mapper.java文件(每个方法输入参数只能是一个,想输入多个通过扩展pojo)编写:

1、mapper.xml中的namespace指定为mapper接口的权限定名:将mapper.xml和mapper.java进行关联


2、mapper.xml中的statement的id就是mapper.java中的方法名:

3、mapper.xml中的statement的parameterType和mapper.java中方法输入参数类型一致

4、mapper.xml中的statement的resultType和mapper.java中方法返回值类型一致

    
    public interface UserMapper {
	    public User findUserById(int id) throws Exception;

5、mapper接口中返回单个对象和集合对象

不管查询记录是单条还是多条,在statement中resultType定义一致,都是单条记录映射的pojo类型。

mapper接口方法返回值,如果返回的单个对象,返回值类型是pojo类型,生成的代理对象内部通过selectOne获取记录,如果返回值类型是集合对象,生成的代理对象内部通过selectList获取记录

public interface UserMapper {
    // 调用selectOne获取记录
	public User findUserById(int id) throws Exception;
    // 调用selectList获取记录
	public List findUserByName(String username) throws Exception;

    
	
	

6、返回值问题

调用statement,返回多条记录,mapper.java中方法的返回类型不能是pojo类型,因为是pojo类型,底层会调用selectOne函数查询结果,会报错!!

7、输入参数问题(解决Mapper.java中方法只能输入一个参数的问题)

可以通过扩展pojo(自己定义pojo包装类型,将要传入的参数传入进去。)

public List findUserList(UserQuery userQuery) throws Exception;

public class UserQueryVo {
	private User user;
	private UserCustom userCustom;
	private List ids;


public class UserCustom extends User {
	
}


    //测试findUserList
	@Test
	public void testFindUserList() throws Exception{
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
		UserQueryVo userQueryVo = new UserQueryVo();
		
		UserCustom userCustom = new UserCustom();
		userCustom.setUsername("小明");
		userQuery.setUserCustom(userCustom);
		
		List list = userMapper.findUserList(userQueryVo);
		sqlSession.close();
		System.out.println(list);
	}

mybatis开发小结:

1、编写SqlMapConfig.xml :引入数据库文件,引入mapper.xml文件

2、编写mapper.xml文件:定义statement,封装成MappedStatement对象返回。

3、编程通过配置文件创建SqlSessionFactory

4、通过sqlSessionFactory获取SqlSession

5、通过SqlSession操作数据库

6、关闭SqlSession!!

因为插入记录需要一个主键返回:有两种方式

mapper.xml文件中

通过LAST_INSERT_ID()获取刚插入记录的自增主键值,在insert语句执行后,执行select LAST_INSERT_ID()就可以获取自增主键

通过使用mysql的uuid机制生成主键:使用uuid生成主键的好处是不考虑数据库移植后主键冲突问题。

    
	
		
        
        
        
        
		
		
		
			select uuid();
		
		Insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
	

 

SqlSessionFactory(会话工厂)

作用:创建SqlSessionFactory

SqlSession:(面向用户的接口,数据库操作方法)

作用:操作数据库

Executor(数据库操作的执行器)

executor是一个接口,有两个实现(默认执行器和缓存执行器)

MappedStatement(mybatis的封装对象)

作用:封装sql语句

在mapper.xml中封装的sql语句返回的就是mappedStatement对象

每一个select就是mappedStatement对象

    
	
	
	
	

mybatis解决jdbc编程问题

1、数据库创建连接、释放频繁造成系统资源浪费从而影响性能,所以使用数据库连接池

解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接。

2、Sql语句写在代码中造成代码不易维护,实际应用啥情况sql变化的可能较大,sql变动需要改变java代码

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

resultMap(返回类型)

resultType与resultMap对比:

resultType:指定输出结果的类型,将sql查询结果映射为java对象。

注意:使用resultType时,sql查询的列名要和resultType指定的pojo的属性名相同,指定相同的属性才可以映射成功,如果sql查询的列名要和resultType指定的pojo的属性名全部不相同,list中无法创建pojo对象。

resultMap:将查询结果映射为java对象

如果查询列名和最终要映射的pojo的属性名不一致,使用resultMap将列名和pojo的属性名做一个对应关系(列名和属性名映射设置)

resultMap


	
    
		
		
		
	

使用resultMap


	

动态sql

#{}和${}完成输入参数的属性值获取,通过OGNL获取parameterType指定pojo的属性名。

#{}:占位符号,好处防止sql注入

${}:sql拼接符号

if和where

通过sql片段可以将sql语句抽取出来,单独定义,在其他statement中可以引用sql片段。

    
	
	
	
	
		
				
					and username like '%${userCustom.username}%'
				
				
					and sex = #{userCustom.sex}
				
				
			
	


 

	
// 这个查询相当于
select * from user where username like '%${userCustom.username}%' and sex = #{userCustom.sex};

foreach

在statement通过foreach遍历parameterType中的集合类型




//相当于
select id,username,birthday from user where username like '%小明%' and id in(id1,id2,id3);



//相当于
select id,username,birthday from user where username like '%小明%' and (id = 16 or id = 24 or id = 36);

resultMap完成一对一、一对多、多对多查询

当关联多个表进行查询的时候,一般resultType无法完成,多使用resultMap完成

resultType实现一对一查询:先确定主查询表 orders,然后确定关联信息表user,通过外键确定连接  

// 查询语句:select orders.*,user.username,user.sex from orders,user where orders.user_id = user.id;

根据查询语句的返回类型确定扩展的pojo类型

public class OrderCustom extends Orders{
    //补充用户信息
    private String username;
    private String sex;
}

mapper.xml中编写:

mapper.java

public interface OrdersMapperCustom{
    public List findOrderUserList() throws Exception;
}

使用resultMap实现一对一

resultMap提供一对一关联查询的映射和一对多关联查询映射,一对一映射思路:将关联查询的信息映射到pojo中。

下列查询语句就是讲关联信息的pojo映射到主查询信息pojo中

// 查询语句:select orders.*,user.username,user.sex from orders,user where orders.user_id = user.id;
public class Orders{
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;

    //关联用户信息
    private User user;
}

mapper.xml

    
	

resultMap定义:

    
	
		
		
		
		
		
		
		
		
		
		
			
			
			
		
	

//SqlMapConfig.xml中定义别名  没有定义别名记得写全限定名


resultType:要自定义pojo保证sql查询列和pojo的属性对应,这种方法简单

resultMap:使用association完成一对一映射需要设置一个resultMap,如果要实现延迟加载就只能用resultMap实现。

resultMap实现一对多查询:

// 查询语句:select orders.*,user.username,user.sex from orders,user where orders.user_id = user.id;

//在这个语句的基础上加一个表关联
select orders.*,user.username,user.sex,orderdetail.id ordertail_id,orderdetail.items_num,orderdetail.items_id from orders,user,orderdetail where orders.user_id = user.id and orders_id = orderdetail.orders_id;
public class Orders{
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;

    //关联用户信息
    private User user;
    private List orderdetails;
}

 

resultMap定义:

    
	
		
			
			
			
		
	

//注意这里用的是collection !! 不是association

 

你可能感兴趣的:(mybatis)