TA的每日心情 | 开心 2021-12-13 21:45 |
---|
签到天数: 15 天 [LV.4]偶尔看看III
|
MyBatis是一个优秀的“不完全的”ORM框架,因为它需要程序员手动写SQL,而相对于Hibernate来说更加的灵活。它完成了关系模型到对象模型的映射,话不多说,直奔主题。
最近公司有一个项目在使用MyBatis作为开发的ORM,所以顺便就来说一点使用MyBatis开发的方式,为了更为纯净,所以此处做与相关框架的整合(如:Spring):
首先,看一下MyBatis的基本框架:

另外一个图示(来自百度):

说明:
1. SqlMapConfig.xml 文件时MyBatis的核心配置文件,可以配置数据源(链接池)、事务…
2. mapper.xml (名字根据需要来定,只要mapper到SqlMapConfig.xml文件中即可)是MyBatis的一个重要的配置文件,用于对javaBean(POJO)做映射。
3. SqlSession 会话——面向程序员的接口。用于对数据库的CRUD
4. Executor 执行器,底层实现,SqlSession内部是通过Executor来操作数据库的,Executor是一个底层封装对象,用户看不到。Executor需要Mapped Statement中封装的数据信息来操作数据库(mapper.xml中配置的信息+POJO)
5. Mapped Statement 是MyBatis的一个封装对象,封装了SQL语句、传入的SQL语句的参数,将SQL查询结果映射(即输出)成的Java对象。
下面,通过三个程序来观察:
1. 简单MyBatis的入门程序
2. 使用Dao 与 DaoImpl 的方法的MyBatis程序
3. 使用动态代理对象的MyBatis
三个程序实现,循序渐进,以为基础:
1、简单MyBatis的入门程序
首先建立一个Java工程,导入MyBatis的核心jar包与依赖jar包:
说明:我使用的MyBatis的版本是: mybatis-3.2.8
jar包准备:

lib中为MyBatis的依赖jar包:

导入数据库驱动jar包(使用MySQL)

新建Java Project:MyBatis_Accessor,在项目下新建一个source folder(相当于CLASSPATH): myBatis_config 以及一个folder: lib ,然后将准备好的jar包Paste到lib中去,然后 Add to Build Path

在myBatis_config中添加相关配置文件:
添加一个log4j的properties 文件(如果你不需要日志,可以不配置,同时可以不导入相关jar包):

- </pre><p></p><p align="left"> </p><p align="left">log4j. properties 配置代码如下:</p><p align="left"></p><pre name="code" class="java"># 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
复制代码
log4j的具体配置如有不明之处,自行Google or Baidu
配置MyBatis的核心配置文件: SqlMapConfig.xml
- <?xml version="1.0"encoding="UTF-8"?>
- <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
- <configuration>
- <!-- 注意:在与Spring整合后,此文件将被废除 -->
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC" />
- <!-- 配置连接池 -->
- <dataSource type="POOLED">
- <property name="driver"value="com.mysql.jdbc.Driver" />
- <property name="url"
- value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"/>
- <property name="username"value="root" />
- <property name="password"value="Jasber0619" />
- </dataSource>
- </environment>
- </environments>
-
- </configuration>
复制代码
接下来,在数据库test里面建一张表user_ 并插入几条数据:

- </pre>现在,创建一个POJO类,在其里面重写了toString()方法以便观察 User:<p></p><p align="left"></p><pre name="code" class="java">package cn.jasberyon.mybatis.pojo;
-
- import java.util.Date;
-
- /**
- *
- * @author Jasber-Yon
- * @date 2015-04-18
- */
- public classUser {
-
- private Integer id;
- private String username;
- private String pwd;
- private String sex;
- private Date birthday;
-
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPwd() {
- return pwd;
- }
- public void setPwd(String pwd) {
- this.pwd = pwd;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public Date getBirthday() {
- return birthday;
- }
- public void setBirthday(Date birthday) {
- this.birthday = birthday;
- }
-
- @Override
- public String toString() {
- return "User [id="+ id + ", username="+ username+ ", pwd="+ pwd+ ", sex="
- +sex+ ", birthday=" + birthday+ "]";
- }
- }
复制代码
然后,我们创建一个Mapper配置文件:user_mapper.xml ,即对刚才的POJO类User与user_表进行映射:
- <?xml version="1.0"encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTDMapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="test">
-
- <select id="findUserByName" parameterType="string"
- resultType="cn.jasberyon.mybatis.pojo.User">
- SELECT * FROM user_ WHERE username=#{id}
- </select>
- </mapper>
复制代码
说明:
1. mapper标签中的 namespace命名空间表示为你的这个mapper命名,在后面测试代码中使用sqlsession.selectOne(“namespace名.select标签中id指定的值”,用户sql查询的参数)
2. select:将select标签内容称为 statement。
3. id:是user_mapper.xml映射文件中唯一标识,statement的id
4. parameterType:指定向SQL(向statement中)中传入参数的类型,注意:string,及参数是MyBatis的方言。
5. #{}:表示一个占位符,{}中的,id表示传入变量名,当传入单个值时,{}中的变量名可以随意。
6. resultType:将SQL查询结果集映射成java对象的类型,注意:其映射成结果集时,不管sql查询的结果是多少条,其类型是代表其中的一条数据的类型,即POJO类型(这在后边的第三种方式中将体现)。
现在,将user_mapper.xml 在 SqlMapConfig.xml 里面进行配置:
- <!-- 加载映射文件 -->
- <mappers>
- <mapper resource="sql_mapper/user_mapper.xml"/>
- </mappers>
复制代码
如图:

好了,现在我们开始编写查询程序(测试) MyBatisTest.java :
- package cn.jasberyon.mybatis.test;
-
- import java.io.IOException;
- 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 cn.jasberyon.mybatis.pojo.User;
-
-
- /**
- *
- * @author Jasber-Yon<br>
- * @date 2015-04-18<br>
- */
- public classMyBatisTest {
-
- public static void main(String[] args) throws IOException {
- //MyBatis的配置文件
- Stringresource= "SqlMapConfig.xml";
- InputStreaminputStream= Resources.getResourceAsStream(resource);
- //创建会话工厂
- SqlSessionFactorysqlSessionFactory= newSqlSessionFactoryBuilder().build(inputStream);
- //从会话工厂中得到会话
- SqlSessionsqlSession= sqlSessionFactory.openSession();
- Useruser= sqlSession.selectOne("test.findUserByName","jasber");
- System.out.println("-------------------------------------result-----------------------------------");
- System.out.println(user);
- System.out.println("------------------------------------------------------------------------------");
- //关闭session
- sqlSession.close();
-
- }
-
- }
复制代码
说明:
User user = sqlSession.selectOne("test.findUserByName","jasber");
一句中“test”为user_mapper.xml文件中mapper标签的namespace指定的命名空间名。“findUserByName”是select标签的唯一标识(指定要执行那一条语句),"jasber"就是我们指定的需要传入查询的参数。
看一下,我们现在的开发环境的项目结构:

那么,现在我们来总结一下,使用MyBatis的基本开发步骤:
1. 建立Java项目,导入相关jar包
2. 配置log4j.properties 文件(可忽略)
3. 配置MyBatis的核心配置文件 SqlMapConfig.xml(文件名可自定义)文件,在此文件中配置数据库的连接数据源、事务、数据库连接池等。
4. 创建一个POJO类:User,其类成员属性与数据库中表字段名一致。生成getter和setter方法,如需要可重写toSting()方法。
5. 编写POJO类与数据库表的映射文件user_mapper.xml(文件名可自定义)。
6. 将映射文件user_mapper.xml配置到SqlMapConfig.xml(是被映射,托管给MyBatis)。
7. 编写查询程序(测试)
现在,在已有的基础上,作插入数据(删除、更新同理,详见MyBatis的API)的操作:
① 到user_mapper.xml 映射配置文件中去配置一条插入语句:
- <insert id="inserUser"parameterType="cn.jasberyon.mybatis.pojo.User">
- <!-- user_ 是对应的表名,设置参数时,#{}内的值要与User中的属性名一致。因为设置了user_表的id自增,所以插入时就不用管它了 -->
- <!-- 注意SQL结束时不要加分号 -->
- insert into user_(username,pwd, sex, birthday) values(#{username},#{pwd},#{sex},#{birthday})
- </insert>
复制代码
截图:

② 编写插入测试(在原操作代码基础上):

- User user2= newUser();
- user2.setUsername("MyBatis插入演示");
- user2.setPwd("ggggg123");
- user2.setSex("1");
- user2.setBirthday(new Date());
- //插入数据
- sqlSession.insert("test.inserUser",user2);
- //CUD操作需要事务,提交事务
- sqlSession.commit();
复制代码
运行成功:

查询验证:

好了,我们已经有了一个大体的了解了,现在来演示一下,另外的两种开发方式:企业中使用MyBatis开发Dao方法:
1.使用Dao 与 DaoImpl 的方法的MyBatis程序
2.使用动态代理对象的MyBatis的Dao实现
1.使用Dao 与 DaoImpl 的方法的MyBatis程序
我们需要编写Dao接口以及Dao接口的实现类:DaoImpl。
开发步骤:
① UserDao.java
② UserDaoImpl.java
③ user_mapper.xml 映射文件
① UserDao.java :
- package cn.jasberyon.mybatis.dao;
-
- import cn.jasberyon.mybatis.pojo.User;
-
- /**
- *
- * @author Jasber-Yon<br>
- * @date 2015-04-18<br>
- */
- public interfaceUserDao {
-
- /**
- * 查询一个用户
- * @param selectId
- * @param username
- * @return
- * @throws Exception
- */
- public UserfindUserByName(String selectId, String username)throwsException;
- }
-
复制代码
② UserDaoImpl.java :
需要注入SqlSesstionFactory,SqlSesstionFactory生成SqlSesstion,如果是MyBatis和Spring进行整合,那么则让Spring管理(IOC)SqlSesstionFactory,将SqlSesstionFactory在Spring容器中以单例方法存在。因为SqlSesstionFactory创建SqlSesstion的方法是线程安全的。
- package cn.jasberyon.mybatis.dao.impl;
-
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
-
- import cn.jasberyon.mybatis.dao.UserDao;
- import cn.jasberyon.mybatis.pojo.User;
-
- public classUserDaoImpl implements UserDao{
-
- private SqlSessionFactory sqlSessionFactory;
-
- publicUserDaoImpl(SqlSessionFactory sqlSessionFactory) {
- // TODO Auto-generated constructor stub
- this.sqlSessionFactory= sqlSessionFactory;
- }
-
- @Override
- public UserfindUserByName(String selectId, String username)throwsException {
- // TODO Auto-generated method stub
- //从会话工厂得到会话 SqlSession
- SqlSessionsession= this.sqlSessionFactory.openSession();
- Useruser= session.selectOne(selectId, username);
- session.close();
- return user;
- }
-
- }
-
复制代码
③ user_mapper.xml 映射文件
- <?xml version="1.0"encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTDMapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="test">
-
- <select id="findUserByName" parameterType="string"
- resultType="cn.jasberyon.mybatis.pojo.User">
- SELECT * FROM user_ WHERE username=#{id}
- </select>
- </mapper>
复制代码
测试(使用JUnit,Eclipse EE 已集成):
测试类:UserDaoImplTest
- package cn.jasberyon.mybatis.dao.impl.j_unit_test;
-
-
- import java.io.InputStream;
-
- import org.apache.ibatis.io.Resources;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- import org.junit.After;
- import org.junit.Before;
- import org.junit.Test;
-
- import cn.jasberyon.mybatis.dao.UserDao;
- import cn.jasberyon.mybatis.dao.impl.UserDaoImpl;
- import cn.jasberyon.mybatis.pojo.User;
-
- public classUserDaoImplTest {
-
- private SqlSessionFactory sqlSessionFactory;
-
- @Before
- public void setUp() throws Exception {
- //MyBatis的配置文件
- Stringresource= "SqlMapConfig.xml";
- InputStreaminputStream= Resources.getResourceAsStream(resource);
- //创建会话工厂
- this.sqlSessionFactory= newSqlSessionFactoryBuilder().build(inputStream);
- }
-
- @Test
- public void test() throws Exception {
- UserDaouserDao= newUserDaoImpl(sqlSessionFactory);
- Useruser= userDao.findUserByName("test.findUserByName","neo");
- System.out.println("-------------------------------------result-----------------------------------");
- System.out.println(user);
- System.out.println("------------------------------------------------------------------------------");
- }
-
- @After
- public void tearDown() throws Exception {
- System.out.println("Testing is Over");
- }
-
- }
复制代码
测试通过:


这个操作的关键点,是要在XxxDaoImpl.java中注入SqlSessionFactory
此时的项目结构(使用到的用红线标注)

下面是另一种方法,也是我推荐的。
2.使用动态代理对象的MyBatis
使用动态代理对象实现,我们只需要编写mapper接口(即Dao接口),不需要再编写其实现类了。
开发步骤:
① userMapper.xml 映射文件
② UserMapper.java (相当于UserDao接口)
① UserMapper.java (相当于UserDao接口)
- package cn.jasberyon.mybatis.mapper;
-
- import cn.jasberyon.mybatis.pojo.User;
-
- /**
- *
- * @author Jasber-Yon<br>
- * @date 2015-04-18<br>
- */
- public interfaceUserMapper {
-
- public User findUserByName(String suername) throws Exception;
- }
复制代码
② userMapper.xml 映射文件
- <?xml version="1.0"encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTDMapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <!-- 注意:此时 namespace是mapper接口的全限定名 -->
- <mapper namespace="cn.jasberyon.mybatis.mapper.UserMapper">
-
- <select id="findUserByName" parameterType="string"
- resultType="cn.jasberyon.mybatis.pojo.User">
- SELECT * FROM user_ WHERE username=#{id}
- </select>
-
- </mapper>
复制代码
③ 在SqlMapConfig.xml 文件中加载 userMapper.xml文件
- <!-- 加载映射文件 -->
- <mappers>
- <mapper resource="sql_mapper/userMapper.xml" />
- </mappers>
-
复制代码
④ 测试:
- package cn.jasberyon.mybatis.dao.impl.j_unit_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 org.junit.After;
- import org.junit.Before;
- import org.junit.Test;
-
- import cn.jasberyon.mybatis.mapper.UserMapper;
- import cn.jasberyon.mybatis.pojo.User;
-
- public classUserMapperTest {
-
- private SqlSessionFactory sqlSessionFactory;
-
- @Before
- public void setUp() throws Exception {
- //MyBatis的配置文件
- Stringresource= "SqlMapConfig.xml";
- InputStreaminputStream= Resources.getResourceAsStream(resource);
- //创建会话工厂
- this.sqlSessionFactory= newSqlSessionFactoryBuilder().build(inputStream);
- }
-
- @After
- public void tearDown() throws Exception {
- System.out.println("Testing is Over");
- }
-
- @Test
- public voidtestFindUserByUsername() throws Exception {
- //得到 SqlSession
- SqlSessionsqlSession= this.sqlSessionFactory.openSession();
- //通过 sqlSession得到UserMapper的代理对象
- UserMapperuserMapper= sqlSession.getMapper(UserMapper.class);
- //调用UserMapper的查询方法
- Useruser= userMapper.findUserByName("克雷格");
- System.out.println("-------------------------------------result-----------------------------------");
- System.out.println(user);
- System.out.println("------------------------------------------------------------------------------");
- }
-
- }
-
复制代码
测试通过:


那么在演示一个查询用户列表的代码:
① 编写(修改一下下,这样该的原因见最后总结)userMapper.xml 文件:
- <?xml version="1.0"encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTDMapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <!-- 注意:此时 namespace是mapper接口的全限定名 -->
- <mapper namespace="cn.jasberyon.mybatis.mapper.UserMapper">
-
- <select id="findUserList" resultType="cn.jasberyon.mybatis.pojo.User">
- SELECT * FROM user_
- </select>
-
- </mapper>
复制代码
② 在UserMapper.java中添加一个方法:public List<User> findUserList()throws Exception;
- package cn.jasberyon.mybatis.mapper;
-
- import java.util.List;
-
- import cn.jasberyon.mybatis.pojo.User;
-
- /**
- *
- * @author Jasber-Yon<br>
- * @date 2015-04-18<br>
- */
- public interfaceUserMapper {
-
- public UserfindUserByName(String username) throwsException;
-
- public List<User>findUserList() throwsException;
- }
复制代码
③ 测试:
- package cn.jasberyon.mybatis.dao.impl.j_unit_test;
- import java.io.InputStream;
- import java.util.List;
-
- 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.After;
- import org.junit.Before;
- import org.junit.Test;
-
- import cn.jasberyon.mybatis.mapper.UserMapper;
- import cn.jasberyon.mybatis.pojo.User;
-
- public classUserMapperTest {
-
- private SqlSessionFactory sqlSessionFactory;
-
- @Before
- public void setUp() throws Exception {
- //MyBatis的配置文件
- Stringresource= "SqlMapConfig.xml";
- InputStreaminputStream= Resources.getResourceAsStream(resource);
- //创建会话工厂
- this.sqlSessionFactory= newSqlSessionFactoryBuilder().build(inputStream);
-
- }
-
-
- @Test
- public void testFindUserList() throws Exception {
- //得到 SqlSession
- SqlSessionsqlSession= this.sqlSessionFactory.openSession();
- //通过 sqlSession得到UserMapper的代理对象
- UserMapperuserMapper= sqlSession.getMapper(UserMapper.class);
- //调用UserMapper的查询方法
- List<User>list= userMapper.findUserList();
- System.out.println("-------------------------------------result-----------------------------------");
- System.out.println(list.size());
- System.out.println("------------------------------------------------------------------------------");
-
- sqlSession.close();
- }
-
-
- @After
- public void tearDown() throws Exception {
- System.out.println("Testing is Over");
- }
-
- }
复制代码
测试通过:


再看一下此时的程序结构(红色标识使用的):

最后我们来总结一下:
除了前面的小结之外,动态代理对象,开发规则:
1. userMapper.xml 的 namespace是UserMapper的(全限定)路径
2. userMapper.xml中的statement的id是 UserMapper.java 中的方法名,必须要一致(但是第一种Dao和DaoImpl的方式则不是这样,因为它是在实现方法中限定的,具体请见代码部分)。
3. userMapper.xml中的statement的parameterType的类型和UserMapper.java 中的方法形参类型一致
4. userMapper.xml 中的statement的resultType的类型和UserMapper.java中的方法返回的值的类型一致(如果返回的是多条,List <User> 那么就是User的全限定路径),resultType的类型应该是查询结果一条记录映射的java对象类型。
5. 是返回一个List还是单个对象,由UserMapper接口的方法返回值类型来决定。
6. 如果返回的是一个List集合,生成的代理对象内部调用 sqlSession.selectList() 方法获取一个集合。
7. 如果返回的是单个对象(一个User),生成的代理对象内部调用 sqlSession.selectOne() 方法获取单个对象。
因为时间关系,没有进行详尽的叙述,尚有不足。
|
|