MyBatis:入门案例

MyBatis介绍

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

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

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

MyBatis架构

1、SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

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即是Mapped statement的id。

6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

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

入门案例:两种方法的CRUD

1、创建MySQL数据库

 

2、创建web工程

3、导入jar包

4、log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

	<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
		<param name="Encoding" value="UTF-8" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
		</layout>
	</appender>
	<logger name="java.sql">
		<level value="debug" />
	</logger>
	<logger name="org.apache.ibatis">
		<level value="info" />
	</logger>
	<root>
		<level value="debug" />
		<appender-ref ref="STDOUT" />
	</root>
</log4j:configuration>

5、mybatisConfig.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>
	<!-- setting:mybatis的全局配置项 -->
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true" />
	</settings>
	<!-- typeAliases:别名 -->
	<typeAliases>
		<typeAlias alias="user" type="org.haiwen.entity.User" />
	</typeAliases>
	<!-- 和spring整合后 environments配置将废除 -->
	<environments default="development">
		<environment id="development">
			<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="org/haiwen/entity/User.xml" />
		<mapper resource="org/haiwen/mapper/UserMapper.xml" />
	</mappers>
</configuration>

6、db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/data
jdbc.username=root
jdbc.password=root

7、User.java,实体类与数据表对应

private Integer id;
private String username;
private String password;

方法一

1、User.xml

namespace :命名空间,用于隔离sql语句,此时可以随意命名。

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

resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。

#{}和${}

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

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

<?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="test">

	<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="org.haiwen.entity.User">
		select * from user where id = #{id}
	</select>
	
	<!-- 自定义条件查询用户列表 -->
	<select id="findUserByUsername" parameterType="java.lang.String" resultType="org.haiwen.entity.User">
		select * from user where username like '%${value}%'
	</select>
	
	<!-- 添加用户 -->
	<insert id="insertUser" parameterType="org.haiwen.entity.User">
		<!-- selectKey将主键返回,需要时再返回 -->
		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
			select LAST_INSERT_ID()
		</selectKey>
		insert into user(username,password) values(#{username},#{password});
	</insert>
</mapper>

2、UserTest.java

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常。

selectList可以查询一条或多条记录。

public class UserTest {

	// 会话工厂
	public SqlSessionFactory sqlSessionFactory;

	@Before
	public void init() throws IOException {
		// 配置文件
		String resource = "mybatisConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	@Test
	public void testFindUserById() throws IOException {
		// 创建数据库会话实例sqlSession
		SqlSession sqlSession = sqlSessionFactory.openSession();
		// 查询单个记录,根据用户id查询用户信息
		User user = sqlSession.selectOne("test.findUserById", 1);
		System.out.println(user);
		sqlSession.close();
	}

	@Test
	public void testFindUserByUsername() throws IOException {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		List<User> list = sqlSession.selectList("test.findUserByUsername", "马");
		for (User user : list) {
			System.out.println(user);
		}
		sqlSession.close();
	}

	@Test
	public void testInsertUser() throws IOException {
		SqlSession sqlSession = null;
		try {
			sqlSession = sqlSessionFactory.openSession();
			User user = new User();
			user.setUsername("马云云");
			user.setPassword("888");
			sqlSession.insert("test.insertUser", user);
			sqlSession.commit();
		} catch (Exception e) {
			e.printStackTrace();
			sqlSession.rollback();
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}
}

方法二:Mapper动态代理

实现原理

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

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

  • Mapper.xml文件中的namespace与mapper接口的类路径相同
  • Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
  • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

1、UserMapper.java

public interface UserMapper {

	// 根据用户id查询用户信息
	public User findUserById(int id) throws Exception;

	// 查询用户列表
	public List<User> findUserByUsername(String username) throws Exception;

	// 添加用户信息
	public void insertUser(User user) throws Exception;
}

2、UserMapper.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="org.haiwen.mapper.UserMapper">

	<!-- 根据id获取用户信息 -->
	<select id="findUserById" parameterType="int" resultType="org.haiwen.entity.User">
		select * from user where id = #{id}
	</select>
	
	<!-- 自定义条件查询用户列表 -->
	<select id="findUserByUsername" parameterType="java.lang.String" resultType="org.haiwen.entity.User">
		select * from user where username like '%${value}%'
	</select>
	
	<!-- 添加用户 -->
	<insert id="insertUser" parameterType="org.haiwen.entity.User">
		<!-- selectKey将主键返回,需要时再返回 -->
		<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
			select LAST_INSERT_ID()
		</selectKey>
		insert into user(username,password) values(#{username},#{password});
	</insert>
</mapper>

3、UserMapperTest.java

public class UserMapperTest extends TestCase {

	private SqlSessionFactory sqlSessionFactory;

	@Override
	protected void setUp() throws Exception {
		// mybatis配置文件
		String resource = "mybatisConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 使用SqlSessionFactoryBuilder创建sessionFactory
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	@Test
	public void testFindUserById() throws Exception {
		//获取session
		SqlSession session = sqlSessionFactory.openSession();
		//获取mapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		//调用代理对象方法
		User user = userMapper.findUserById(1);
		System.out.println(user);
		//关闭session
		session.close();
	}

	@Test
	public void testFindUserByUsername() throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		List<User> list = userMapper.findUserByUsername("马");
		for (User user : list) {
			System.out.println(user);
		}
	}

        @Test
	public void testInsertUser() throws Exception {
		// 获取session
		SqlSession session = sqlSessionFactory.openSession();
		// 获取mapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		// 要添加的数据
		User user = new User();
		user.setUsername("马云云");
		user.setPassword("888");
		// 通过mapper接口添加用户
		userMapper.insertUser(user);
		// 提交
		session.commit();
		// 关闭session
		session.close();
	}
}

MySQL自增主键返回

keyProperty:返回的主键存储在pojo中的哪个属性

order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after

resultType:返回的主键是什么类型

LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值

<insert id="insertUser" parameterType="org.haiwen.entity.User">
	<!-- selectKey将主键返回,需要时再返回 -->
     <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
         select LAST_INSERT_ID()
     </selectKey>
    insert into user(username,password) values(#{username},#{password});
</insert>

MySQL使用uuid实现主键

注意这里使用的order是“BEFORE”

<insert id="insertUser" parameterType="org.haiwen.entity.User">
	<!-- selectKey将主键返回,需要时再返回 -->
     <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
         select uuid()
     </selectKey>
    insert into user(id,username,password) values(#{id},#{username},#{password});
</insert>

Oracle使用序列生成主键

<insert id="insertUser" parameterType="org.haiwen.entity.User">
	<!-- selectKey将主键返回,需要时再返回 -->
     <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
         select 自定义序列.NEXTVAL from dual
     </selectKey>
    insert into user(id,username,password) values(#{id},#{username},#{password});
</insert>
发布了202 篇原创文章 · 获赞 37 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/lovecuidong/article/details/101064860