mybaties基础篇

mybatis专栏 https://blog.csdn.net/worn_xiao/category_6530299.html?spm=1001.2014.3001.5482

一什么是Mybatis:

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

Mybatis通过xml或注解的statement,Preparestatement,CallableStatement配置起来,并通过java对象和statement中的生成最终执行的sql语句,最后由mybaties框架执行sql并返回最终对象.

二 Mybatie,jdbc,hibernate的对比

2.1 Jdbc

public static void main(String[] args) {
                 Connectionconnection = null;
                 PreparedStatementpreparedStatement = null;
                 ResultSetresultSet = null;
                 try {
                      Class.forName("com.mysql.jdbc.Driver");
                      connection=  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
                      String sql = "select * from user whereusername = ?";
                      preparedStatement= connection.prepareStatement(sql);
                      preparedStatement.setString(1,"王五");
                      resultSet =  preparedStatement.executeQuery();
                      while(resultSet.next()){
                            System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
                      }
                 }catch (Exception e) {
                      e.printStackTrace();
                 }finally{
                      if(resultSet!=null){
                            try {
                                  resultSet.close();
                            }catch (SQLException e) {
                                  e.printStackTrace();
                            }
                      }

                      if(preparedStatement!=null){
                            try {
                                  preparedStatement.close();
                            }catch (SQLException e) {
                                  e.printStackTrace();
                            }
                      }

                      if(connection!=null){
                            try {
                                  connection.close();
                            }catch (SQLException e) {
                                  e.printStackTrace();
                            }
                      }
                 }
           }

Jdbc存在的问题与解决方案

一:频繁的开启或者关闭数据库连接,影响数据库性能。

二:代码中存在硬编码,数据库硬编码和SQL执行部门的硬编码。

解决上面的问题:通过xml的方式来配置。

2.2 Mybaties的技术特点:

1.        可以直接编写sql,并且对sql进行性能优化。

2.        学习门槛低,成本低,只要会sql就很快能够上手。

3.        直接编写sql,灵活性好,易于维护。

4.        对数据库无关性的支持不太好,如果数据库发生变更,要写多套代码。

5.        需要编写结果映射

2.3 Hibernate

1标准的orm框架,程序员不需要编写sql语句。

2 具有良好的数据库无关性,数据库发生改变的话无需变更配置,但是如果植入了sql的话,数据库变更就要进行变更。

3 学习门槛高,在or映射的时候既要考虑性能,也要权衡映射关系。

4 不能自主进行sql映射的优化。

Mybaties适合的场景:业务灵活多变的业务系统。

Hibernate适合的场景:业务固定的系统, 比如OA系统与CRM系统。

三 Mybaties工作原理图

1 mybaties配置文件:(mybaties全局配置文件与映射文件)

全局配置文件配置了数据源,事务等信息,映射文件配置了SQL执行相关的信息。

2 mybaties通过读取配置文件,构造出sqlsessionFactory,即构造出会话工厂。

3 通过sqlsessionFactory来创建会话sqlsession,并且通过sqlsession来直接连接数据库

4 sqlsession本身不能直接连接数据库,它是通过executor执行器来操作数据库的,executor本身有两个执行器,一个是普通的执行器,一个是默认的执行器。这个过程是同过一个mappper代理来完成的。

5 executor把要执行的sql信息封装到了一个底层mappedStatement对象中,该对象包括sql语句,输入参数映射信息,输出结果的映射信息。

四 全局配置文件常见配置sqlMapConfig.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>
<environments default="development">
	<environment id="development">
		<transactionManager type="JDBC"></transactionManager>
		<dataSource type="POOLED">
			<property name="driver" value="com.mysql.jdbc.Driver"/>
			<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
			<property name="username" value="root"/>
			<property name="password" value="root"/>
		</dataSource>
	</environment>
</environments>
<typeAliases>
		<!-- 单个定义别名 -->
		<typeAlias type="cn.itcast.mybatis.po.User" alias="user"/>
		
		<!-- 批量定义别名(推荐) -->
		<!-- [name]:指定批量定义别名的类包,别名为类名(首字母大小写都可) -->
		<package name="cn.itcast.mybatis.po"/>
</typeAliases>
<mappers>
	<mapper resource="sqlmap/User.xml"/>
</mappers>

</configuration>
	

五 mybaties模拟基本的增删改查

5.1 模拟需求: 根据用户id查询用户信息

在User.xml中添加以下代码:

<mapper namespace="test">
    <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
       SELECT * FROMUSER WHERE id = #{id}
    </select>
</mapper>

Namespace:命名空间,它的作用是对SQL进行分类化管理,是SQL的隔离标识,如果是使用mapper代理做开发它有很大的作用。

Id:statement的id,命名空间内标签的唯一标识。

resultType:查询出单条结果集,所对应的java类型。

#{}: 标识一个占位符?

#{id}:表示该占位符待接收参数的名称为id,简单类型#{}里面的参数名称可以是任意定义的。

5.2 模拟需求: 根据用户名称模糊查询用户信息

User.xml中配置如下

<mapper namespace="test">
   <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
       SELECT * FROMUSER WHERE id = #{id}
   </select>
</mapper>

${} 表示拼接sql字符串。

${value} 表示要拼接的是简单类型的参数。

1:如果参数为简单类型时,里面的参数必须为value

2:${} 会引起sql注入,一般不推荐使用,但是有些场景必须使用${} 比如order by ${column}

5.3 模拟需求: 添加用户信息

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    INSERT INTOUSER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})
</insert>

#{} 表示占位符,就相当于原生sql预编译时的?,最终将会由executor进行调用jdbc的欲编译语句进行替换。

5.4 需求模拟: 删除用户

<delete id="deleteUser" parameterType="int">
    DELETE FROM USERWHERE id= #{id}
</delete>

5.5 需求模拟:修改用户

<delete id="deleteUser" parameterType="int">
    DELETE FROM USERWHERE id= #{id}
</delete>

六 mybaties主键生策略

6.1 自增主键的生成策略,以mysql为例来描述主键生成策略。

insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
	<selectKey keyProperty="id" resultType="int" order="AFTER">
		SELECT LAST_INSERT_ID()
	</selectKey>
	INSERT INTO USER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})
</insert>

SelectKey标签:通过selectkey查询来生成主键。

KeyProperty:指定存放生成主键的属性。

resultType 主键所对应的java类型

order 制定该查询与句相对于insert语句的执行顺序,如果是自增主键应该在插入之前先执行,生成id,如果是主键回调,则应该放在插入之后执行。

6.2 主键生成策略之uuid()

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    <selectKey keyProperty="id" resultType="string"order="BEFORE">
       SELECT UUID()
    </selectKey>
    INSERT INTOUSER(id,username,sex,birthday,address) VALUES (#{id},#{username},#{sex},#{birthday},#{address})
</insert>

再插入之前先调用mysql的函数生成一个唯一的UUID,UUID生成的字符串是35位的。

6.3主键返回之oracle序列:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    <selectKey keyProperty="id" resultType="int"order="BEFORE">
       SELECT user_seq.nextval()FROM dual
    </selectKey>
    INSERT INTOUSER(id,username,sex,birthday,address) VALUES (#{id},#{username},#{sex},#{birthday},#{address})
</insert>

七 关键点总结

parameterType指定输入参数的java类型,可以填写别名或Java类的全限定名。

resultType指定输出结果的java类型,可以填写别名或Java类的全限定名。

#{}和${}

#{}:相当于预处理中的占位符?。

#{}里面的参数表示接收java输入参数的名称。

#{}可以接受HashMap、简单类型、POJO类型的参数。

当接受简单类型的参数时,#{}里面可以是value,也可以是其他。

#{}可以防止SQL注入。

${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。

${}会引起SQL注入,所以要谨慎使用。

${}可以接受HashMap、简单类型、POJO类型的参数。

当接受简单类型的参数时,${}里面只能是value。

八 Mybaties持久层开发方式

7.1 方式一:dao方式开发

操作步骤:

1 编写实体类

2 编写实体类xml映射文件

3 配置全局xml文件

4 加载全局文件,构建sqlsessionfactory

5 通过sqlsessionfactory创建sqlsession

6 通过sqlsession调用远程的select等方法

开发dao接口:

public interface UserDao {
	public User findUserById(int id); 
	public List<User> findUsersByName(String username);
	public void insertUser(User user);
}

SqlSessionFactoryBuilder

它的作用只是通过配置文件创建SqlSessionFactory,所以只要创建出SqlSessionFactory,它就可以销毁了。所以说,它的生命周期是在方法之内。

SqlSessionFactory

它的作用是创建SqlSession的工厂,工厂一旦创建,除非应用停掉,不要销毁。

所以说它的生命周期是在应用范围内。这里可以通过单例模式来管理它。

在mybatis整合spring之后,最好的处理方式是把SqlSessionFactory交由spring来做单例管理。

SqlSession

SqlSession是一个面向用户(程序员)的接口,它的默认实现是DefaultSqlSession。

Mybatis是通过SqlSession来操作数据库的。SqlSession中不仅包含要处理的SQL信息,还包括一些数据信息,所以说它是线程不安全的,因此它最佳的生命周期范围是在方法体之内。

public class UserDaoImpl implements UserDao {
	private SqlSessionFactory sqlSessionFactory;
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
		this.sqlSessionFactory = sqlSessionFactory;
	}
	@Override
	public User findUserById(int id) {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		return sqlSession.selectOne("test.findUserById", id);
	}
	@Override
	public List<User> findUsersByName(String username) {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		return sqlSession.selectList("test.findUsersByName", username);
	}
	@Override
	public void insertUser(User user) {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.insert("test.insertUser", user);
	}
}

测试方法:

public class UserDaoTest {
	private SqlSessionFactory sqlSessionFactory;
	
	@Before
	public void setUp() throws Exception { 
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

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

	@Test
	public void testFindUsersByName() { 
		UserDao userDao = new UserDaoImpl(sqlSessionFactory); 
		List<User> list = userDao.findUsersByName("小明");
		System.out.println(list);
	}

	@Test
	public void testInsertUser() {
		
		UserDao userDao = new UserDaoImpl(sqlSessionFactory); 
		User user = new User();
		user.setUsername("东哥3");
		user.setAddress("清河宝盛西里3"); 
		userDao.insertUser(user);
		System.out.println(user.getId());
	}
}

Dao开发方式存在的一些问题:

1 存在一些模板代码比如创建sqlsessionfactory,创建sqlsession,关闭sqlsession。

2 存在一些硬编码,比如statement,参数之类的。

7.2 方式二 mapper方式开发

Mapper的开发规范:

1 mapper接口的全限定名要与xml配置文件中的namespace相同。

2 mapper接口中的方法名称要和statement中的id一致。

3 mapper接口中的参数只能有一个,且类型要与statement中是parametertype的类型一致。

4 mapper接口的返回值类型要和statement中的resulttype与resultmap一致。

操作:

根据需求创建po类

编写全局配置文件

根据需求编写映射文件

加载映射文件

编写mapper接口

编写测试代码

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">
<!-- namespace:此时用mapper代理方式,它的值必须等于对应mapper接口的全限定名  -->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">

	<!-- 根据用户ID,查询用户信息 -->
	<!-- 
		[id]:statement的id,要求在命名空间内唯一  
		[parameterType]:入参的java类型,可是是简单类型、POJO、HashMap
		[resultType]:查询出的单条结果集对应的java类型
		[#{}]: 表示一个占位符?
		[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
	 -->
	<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
		SELECT * FROM USER WHERE id = #{id}
	</select>
	
	
	<!-- 根据用户名称模糊查询用户信息列表 -->
	<!-- 
		[${}]:表示拼接SQL字符串,即不加解释的原样输出
	 	[${value}]:表示要拼接的是简单类型参数。
		1、如果参数为简单类型时,${}里面的参数名称必须为value 
		2、${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如order by ${colname}
	-->
	<select id="findUsersByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
		SELECT * FROM USER WHERE username LIKE '%${value}%'
	</select>
	
	<!-- 添加用户之自增主键返回(selectKey方式) -->
<!—
[selectKey标签]:通过select查询来生成主键
	[keyProperty]:指定存放生成主键的属性
	[resultType]:生成主键所对应的Java类型
	[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句,此时选用AFTER
	[last_insert_id]:MySQL的函数,要配合insert语句一起使用-->
	<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		INSERT INTO USER(username,sex,birthday,address) VALUES (#{username},#{sex},#{birthday},#{address})
	</insert>
</mapper>

在全局配置文件中配置mapper的映射

<mappers>
	<mapper resource="sqlmap/User.xml"/>
	<mapper resource="mapper/UserMapper.xml"/>
</mappers>

编写mapper接口

publicinterface UserMapper {

         publicUser findUserById(int id);

         publicList<User> findUsersByName(String username);

         publicvoid insertUser(User user);

}

测试代码:

public class UserMapperTest {
	// 声明全局的SqlSessionFactory
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void setUp() throws Exception { 
		String resource = "SqlMapConfig.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	@Test
	public void testFindUserById() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
		User user = userMapper.findUserById(1);

		System.out.println(user);
		sqlSession.close();

	}

	@Test
	public void testFindUsersByName() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
		List<User> list = userMapper.findUsersByName("小明");
		System.out.println(list);
		sqlSession.close();
	}

	@Test
	public void testInsertUser() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
		User user = new User();
		user.setUsername("东哥4");
		user.setAddress("清河宝盛西里4"); 
		userMapper.insertUser(user);
		System.out.println(user.getId());
		sqlSession.commit();
		sqlSession.close();
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值