mybatis学习笔记(一)

目录

一、mybatis介绍

二、传统的jdbc编程的缺点。

三、mybatis的架构

四、mybatis入门起步

五、mybatis总结

六、Dao层开发

七、SqlMapConfig.xml配置文件


一、mybatis介绍

mybatis本来是apache的一个开源项目叫ibatis,2010年这个项目由apach software foundation迁移到了google code,改名为mybatis,2013年迁移到github。

mybatis是一个优秀的持久层框架,它对jdbc的数据库操作过程进行了封装,使得开发车只需要关注sql本身,而不需要花费精力去处理例如注册驱动,创建连接啥的一系列复杂问题,完全避免的这一套的繁琐复杂的过程。

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

二、传统的jdbc编程的缺点。

2.1 jdbc的编程步骤

1.加载数据库驱动

Class.forName("com.mysql.jdbc.driver");

2.创建并获取数据库连接

DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8,"root","root");

3.创建jdbc statement对象

String sql = "select * from user where username=?";
PreparedStatement statement = connection.preparedStatement(sql);

4.设置sql语句和其中的参数

statement.setString(1,"张三");

5.通过statement执行sql获取结果

ResultSet resultSet = statement.executeQuery();

6.对sql执行结果进行解析处理

while(resultSet.next()){
    System.out.println(resultSet.getString("id")+" "+resulSet.getString("username"));
}

7.释放资源(resultset,preparedStatement,connection)

resultSet.close();
statement.close();
connection.close();

2.2 jdbc问题总结:

1.数据库连接频繁创建造成资源浪费,影响性能,这一步可以使用数据库连接池来解决问题。

2.sql语句再代码中硬编码,不易维护,实际应用中的sql变化的可能性较大,变的时候需要改java代码。(不过这都不是事啊,感觉,啥时候不改代码,一直再修改,从未停止。)

3.使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

4.对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

三、mybatis的架构

1.SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息,mapper啥的也在里边。

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2.通过mybatis的环境等配置信息构造SqlSessionFactory即 会话工厂。

3.由会话工厂创建sqlsession会话,操作数据库需要通过sqlsession进行。

4.mybatis底层定义了executor执行器接口操作数据库,executor接口有两个实现,一个是基本执行器,一个是缓存执行器。

5.Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mappped Statement的id。

6.Mapped Statement 对sql 执行输入结果进行定义,包括HashMap、基本类型,pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc中对结果的解析处理过程。

 四、mybatis入门起步

 4.1 mybatis的下载

地址:https://github.com/mybatis/mybatis-3/releases

mybatis-3.2.7.jar        mybatis的核心包

lib文件夹     mybatis的依赖包所在

mybatis-3.2.7.pdf    mybatis使用手册

jdbc数据库驱动包    mysql-connector-java-5.1.7-bin.jar

4.2 环境搭建

4.2.1.新建一个web工程,起名为mybatis,导包

4.2.2.添加配置文件

log4j.properties文件作为日志输出的配置

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

SqlMapConfig.xml 作为mybatis的环境配置文件

<?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>
	<!-- 和spring整合后 environments配置将废除 -->
	<environments default="development">
		<environment id="development">
			<!-- 使用jdbc事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
</configuration>

4.2.3 创建pojo类,与相应的数据表对应

package com.baidu.domain;

public class User {
	private int id;
	private String name;
	private int age;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ",name=" + name + ",age=" + age + "]";
	}
}

4.2.4 创建mapper.xml映射文件

这里我们先创建一个UserMapper.xml 来映射user表。

<?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 指定一个唯一的namespace,习惯上设置成包名+sql映射文件名,这样就能够保持唯一了
 -->
<mapper namespace="com.baidu.mapper.UserMapper">
	<select id="getUser" parameterType="int" resultType="com.baidu.domain.User">
		select* from users where id = #{id}
	</select>
</mapper>

其中id为 statement的id,保持在一个mapper唯一。

parameterType 声明输入参数的类型,也就是id的类型为int。

resultType 声明输出结果的类型,应该填写pojo的全路径 带上包名的那种,因为mybatis里边要通过反射拿。

#{} 是输入参数的占位符,类似于jdbc中的?

4.2.5 让mybatis加载这个mapper

<?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>

	<environments default="development">
		<environment id="development">
			<!-- 使用jdbc事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>

	<mappers>
		<mapper resource="com/baidu/mapper/UserMapper.xml" />
	</mappers>
</configuration>

4.2.6 进行测试

package com.baidu.test;

import java.io.InputStream;

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 com.baidu.domain.User;

public class TestDemo {

	public static void main(String[] args) {
		try {
			
			InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
			
			SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
			
			SqlSession session = sessionFactory.openSession();
			
			String statement= "com.baidu.mapper.UserMapper.getUser";
			User user = session.selectOne(statement,1);
			
			System.out.println(user);
			session.close();
			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
}

输出结果

4.2.7 模糊查询

方法1:

<!-- 如果返回多个结果,mybatis会自动把返回的结果放在list容器中 -->
<!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername1" parameterType="string"         
            resultType="com.baidu.domain.User">
		    select * from users where name like #{name}
</select>

关键代码:

String statement= "com.baidu.mapper.UserMapper.queryUserByUsername1";
User user = session.selectOne(statement,"%王%");
			

方法2:

 <!-- 如果传入的参数是简单数据类型,${}里面必须写value -->
<select id="queryUserByUsername2" parameterType="string"
		resultType="com.baidu.domain.User">
		SELECT * FROM `users` WHERE name LIKE '%${value}%'
</select>

关键代码:

String statement= "com.baidu.mapper.UserMapper.queryUserByUsername2";
User user = session.selectOne(statement,"五");

4.3 小结

4.3.1 #{}和${}

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。#{}可以接受简单类型或者pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或者其他名称。

${}表示拼接sql串,通过${}可以将paramterType传入的内容拼接再sql中且不进行jdbc类型转换,${}可以接受简单类型或者pojo属性值,如果paramterType传输单个简单类型值,${}括号中只能是value。(扯淡,为什么)

4.3.2 parameterType和resultType

parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接再sql中。

resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放置到List。

4.3.3 selectOne和selectList

selectOne查询一条记录,如果出现多条则抛出异常,selectList可以查询一条或者多条。

4.4 实现添加用户

UserMapper.xml中的添加如下配置内容:

<!-- 保存用户 -->
<insert id="saveUser" parameterType="com.baidu.domain.User">
	INSERT INTO `users` (name,age) VALUES (#{name},#{age})
</insert>

关键代码:

String statement = "com.baidu.mapper.UserMapper.saveUser";

User user = new User();
user.setAge(58);
user.setName("lisisi");
int result = session.insert(statement, user);

System.out.println(result);

插入成功:

4.5 自增主键返回

方法一:

<!-- 保存用户 -->
	<insert id="saveUserKey" parameterType="com.baidu.domain.User">
		<!-- selectKey 标签实现主键返回 -->
		<!-- keyColumn:主键对应的表中的哪一列 -->
		<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
		<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
		<!-- resultType:设置返回的id的类型 -->
		<selectKey keyColumn="id" keyProperty="id" order="AFTER"
			resultType="int">
			SELECT LAST_INSERT_ID()
		</selectKey>
		INSERT INTO `users`	(name,age) VALUES (#{name},#{age})
	</insert>

注意:这里的selectKey标签的order属性是AFTER,用于自增id,因为插入之后才知道,如果是BEFORE,则用于uuid,是插入之前就生成的。

关键代码:

String statement = "com.baidu.mapper.UserMapper.saveUserKey";
User user = new User();
user.setAge(158);
user.setName("自增主键");
int result = session.insert(statement, user);
			
System.out.println(user.getId());

这里需要用user.getId() 来获取,mybatis自动把id设计进去了。

方法二:

<!-- 保存用户 -->
<insert id="saveUserKey2" keyProperty="id" useGeneratedKeys="true"                         
        parameterType="com.baidu.domain.User">
		INSERT INTO `users` (name,age) VALUES (#{name},#{age})
</insert>

关键代码一样。

4.6 修改用户

UserMapper.xml中的添加如下配置内容:

<!-- 更新用户 -->
<update id="updateUserById" parameterType="com.baidu.domain.User">
	UPDATE `users` SET
	name = #{name},age = #{age} WHERE id = #{id}
</update>

关键代码:

String statement = "com.baidu.mapper.UserMapper.updateUserById";
User user = new User();                                         
user.setId(10);                                                 
user.setAge(1000);                                              
user.setName("自增主键2修改");                                        
int result = session.update(statement, user);                   

4.7 删除用户

UserMapper.xml中的添加如下配置内容:

<!-- 删除用户 -->                                    
<delete id="deleteUserById" parameterType="int"> 
	delete from users where                      
	id=#{id}                                     
</delete>                                        

关键代码:

SqlSession session = sessionFactory.openSession();              
                                                                
String statement = "com.baidu.mapper.UserMapper.deleteUserById";
                                                                
int result = session.update(statement, 10);                     
                                                                
System.out.println(result);                                     

五、mybatis总结

5.1 解决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定义输出结果的类型。

5.1 与hibernate的区别

mybatis和hibernate不同,它不完全是一个orm框架,因为mybatis需要程序员自己编写sql语句。mybatis可以通过xml或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

六、Dao层开发

 传统的dao层开发需要先编写接口层,再编写实现层,写起来有点麻烦,mybatis推荐用动态代理的方式开发dao层,省去了我们写实现层的一些代码。

6.1 开发规范

mapper接口开发方法只需要程序按编写mapper接口(相当于dao接口),由mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边dao接口实现类方法。

mapper接口开发需要遵循以下规范:

1.mapper.xml文件中的namespace与mapper接口的类路径相同

2.mapper接口方法名和mapper.xml中定义的每个statement的id相同。

3.mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同。

4.mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。

6.2  开发方式

定义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 指定一个唯一的namespace,习惯上设置成包名+sql映射文件名,这样就能够保持唯一了
 -->
<mapper namespace="com.baidu.mapper.UserMapper">
	<select id="getUser" parameterType="int" resultType="com.baidu.domain.User">
		select* from users where id = #{id}
	</select>
	
	<!-- 保存用户 -->
	<insert id="saveUser" parameterType="com.baidu.domain.User">
		INSERT INTO `users`
		(name,age) VALUES
		(#{name},#{age})
	</insert>
	
	<!-- 更新用户 -->
	<update id="updateUserById" parameterType="com.baidu.domain.User">
		UPDATE `users` SET
		name = #{name},age = #{age} WHERE id = #{id}
	</update>
	
	<!-- 删除用户 -->
	<delete id="deleteUserById" parameterType="int">
		delete from users where
		id=#{id}
	</delete>
</mapper>

定义UserMapper接口,在com.baidu.mapper包下边,并且和mapper.xml中的namespace保持一致,不然会报错。

package com.baidu.mapper;

import java.util.List;

import com.baidu.domain.User;

public interface UserMapper {
	
	List<User> getUser(int id);
	
	void saveUser(User user);
	
	void updateUserById(int id);
	
	void deleteUserById(int id);
}

加载mapper.xml文件

<mappers>
	<mapper resource="com/baidu/mapper/UserMapper.xml" />
</mappers>

关键代码:

InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); 
                                                                    
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()   
		.build(is);                                                 
                                                                    
SqlSession session = sessionFactory.openSession();                  
                                                                    
UserMapper mapper = session.getMapper(UserMapper.class);            
                                                                    
System.out.println(mapper.getUser(4));                              
session.close();                                                    

七、SqlMapConfig.xml配置文件

7.1 配置内容的顺序

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

     transactionManager(事务管理)

     dataSource(数据源)

mappers(映射器)

7.2 properties(属性)

SqlMapConfig.xml可以引用java属性文件中的配置信息,定义db.properties文件,如图:

SqlMapConfig.xml中的environment配置改写成如下:

<environments default="development">
		<environment id="development">
		<transactionManager type="JDBC"></transactionManager>
		<dataSource type="POOLED">
			<property name="driver" value="${driver}"/>
			<property name="url" value="${url}"/>
			<property name="username" value="${username}"/>
			<property name="password" value="${password}"/>
		</dataSource>
		</environment>
</environments>

7.3 typeAliases(类型别名)

mybatis默认支持的别名

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

map

Map

自定义别名

<?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>
		<!-- 单个别名定义 -->
		<typeAlias alias="User" type="com.baidu.domain.User" />
		<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
		<package name="com.baidu.domain" />
	</typeAliases>
	
	<environments default="development">
		<environment id="development">
		<transactionManager type="JDBC"></transactionManager>
		<dataSource type="POOLED">
			<property name="driver" value="${driver}"/>
			<property name="url" value="${url}"/>
			<property name="username" value="${username}"/>
			<property name="password" value="${password}"/>
		</dataSource>
		</environment>
	</environments>
</configuration>

这样的话UserMapper.xml中的parameterType和resultType就可以使用别名了,就可以直接写User,而不用写包名了。mybatis根据配置的typeAliases自动识别。

<?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 指定一个唯一的namespace,习惯上设置成包名+sql映射文件名,这样就能够保持唯一了
 -->
<mapper namespace="com.baidu.mapper.UserMapper">
	<select id="getUser" parameterType="int" resultType="User">
		select* from users where id = #{id}
	</select>
</mapper>

7.4 mappers映射器的配置方法

7.4.1 使用相对于类路径的资源(当前使用的方式)

<mapper resource="com/baidu/mapper/UserMapper.xml" />

7.4.2 使用mapper接口类路径

<mapper class="com.baidu.mapper.UserMapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

7.4.3 注册指定包下所有的mapper接口

<package name="com.baidu.mapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值