javaweb实训第六天下午——Mybatis基础(1)https://developer.aliyun.com/article/1415142
4.3.2.实现
核心配置文件:MyBatis-Config.xml <configuration> <!-- 引入配置文件信息,这里不能加classpath:。 resource:引入类路径下的资源,即classpath,所以不需要写classpath: url:引入网络路径或磁盘路径下的资源 --> <properties resource="db.properties"></properties> <!-- 环境们 (很多环境的意思) default:默认使用哪一个环境(必需对应一个环境的id) --> <environments default="development"> <!-- 一个环境 id:为这个环境取唯一一个id名称 --> <environment id="development"> <!-- 事务管理 type:JDBC(支持事务)/MANAGED(什么都不做) --> <transactionManager type="JDBC" /> <!-- 数据源, 连接池 type(POOLED):MyBatis自带的连接池 --> <dataSource type="POOLED"> <!-- 连接数据库的参数:直接写死的方式 --> <!-- <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql:///mydb" /> <property name="username" value="root" /> <property name="password" value="admin" /> --> <!-- 连接数据库的参数:使用属性文件的方式 --> <property name="driver" value="${db.driver}" /> <property name="url" value="${db.url}" /> <property name="username" value="${db.username}" /> <property name="password" value="${db.password}" /> </dataSource> </environment> </environments> <!-- 这个mappers代表的是相应的ORM映射文件 --> <mappers> <mapper resource="cn/itsource/domain/ProductMapper.xml" /> </mappers> </configuration>
属性文件:db.properties
db.driver=com.mysql.jdbc.Driver db.url=jdbc:mysql:///test0303 db.username=root db.password=admin
映射文件:
我们的映射文件(也称之为mapper文件)一般情况下是和它对应的domain实体类在同一个包下;
这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
例如实体类有:
cn.itsource.domain.Product
映射文件名为:
cn/itsource/domain/ProductMapper.xml
namespace的名称通常是接口的完全限定名;
- 除了MyBatis支持的类型,其它的类型都通通使用全限定
<?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的主要功能就是写sql mapper:根 namespace:命令空间 (用来确定唯一)以前这个是可以不加的,现在必需加 namespace的值:接口的完全限定名 --> <mapper namespace="cn.itsource.dao.IProductDao"> <!-- select :这里面写查询语句 id:用来确定这条sql语句的唯一 以后我们确定唯一,也就是找sql语句 : namespace + id 例: cn.itsource.mybatis.day1._1_hello.IProductDao.get parameterType : 传入的参数类型 long:大Long _long:小long (具体的对应请参见文档) resultType : 结果类型(第一条数据返回的对象类型)自己的对象一定是完全限定类名 --> <select id="get" parameterType="long" resultType="cn.itsource.domain.Product"> select * from product where id = #{id} </select> </mapper>
入门代码:
@Override public Product get(Long id) { SqlSession session = null; try { Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); session = sqlSessionFactory.openSession(); // 两个参数:mapper的nameSpace+id的路径,和需要的参数 return session.selectOne(NAME_SPACE+"get", id); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("使用get方法出错:" + e.getMessage()); } finally { if (session != null) { session.close(); } } }
4.4.其他实现
package cn.itsource.mybatis._01_hello.dao.impl; import cn.itsource.mybatis._01_hello.dao.IProductDao; import cn.itsource.mybatis._01_hello.domain.Product; 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 java.io.Reader; import java.util.List; /** * dao实现 * * insert:添加,事务控制 * delete:删除,事务控制 * update:修改,事务控制 * selectOne:查询一个 * SelectList:查询多个 */ public class ProductDaoImpl implements IProductDao { @Override public void save(Product product) { SqlSession sqlSession = null; try { //1 准备配置文件 ok //2 创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //3 获取sqlSession做操作 sqlSession = sqlSessionFactory.openSession(); //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值 sqlSession.insert("cn.itsource.dao.IProductDao.save",product); //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务 sqlSession.commit(); }catch (Exception e){ e.printStackTrace(); sqlSession.rollback(); }finally { if (sqlSession != null) { sqlSession.close(); } } } @Override public void remove(Long id) { SqlSession sqlSession = null; try { //1 准备配置文件 ok //2 创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //3 获取sqlSession做操作 sqlSession = sqlSessionFactory.openSession(); //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值 sqlSession.delete("cn.itsource.dao.IProductDao.remove",id); //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务 sqlSession.commit(); }catch (Exception e){ e.printStackTrace(); sqlSession.rollback(); }finally { if (sqlSession != null) { sqlSession.close(); } } } @Override public void update(Product product) { SqlSession sqlSession = null; try { //1 准备配置文件 ok //2 创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //3 获取sqlSession做操作 sqlSession = sqlSessionFactory.openSession(); //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值 sqlSession.update("cn.itsource.dao.IProductDao.update",product); //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务 sqlSession.commit(); }catch (Exception e){ e.printStackTrace(); sqlSession.rollback(); }finally { if (sqlSession != null) { sqlSession.close(); } } } @Override public Product loadById(Long id) { SqlSession sqlSession = null; try { //1 准备配置文件 ok //2 创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //3 获取sqlSession做操作 sqlSession = sqlSessionFactory.openSession(); //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值 return sqlSession .selectOne("cn.itsource.dao.IProductDao.loadById",id); }catch (Exception e){ e.printStackTrace(); }finally { if (sqlSession != null) { sqlSession.close(); } } return null; } @Override public List<Product> loadAll() { SqlSession sqlSession = null; try { //1 准备配置文件 ok //2 创建SqlSessionFactory Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //3 获取sqlSession做操作 sqlSession = sqlSessionFactory.openSession(); //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值 return sqlSession .selectList("cn.itsource.dao.IProductDao.loadAll"); }catch (Exception e){ e.printStackTrace(); }finally { if (sqlSession != null) { sqlSession.close(); } } return null; } } package cn.itsource.mybatis._01_hello.dao; import cn.itsource.mybatis._01_hello.dao.impl.ProductDaoImpl; import cn.itsource.mybatis._01_hello.domain.Product; import org.junit.Test; /** * 打印快捷方式:obj.sout * 快速省略测试:类里面-右键-goto-junit4-勾上 */ public class IProductDaoTest { IProductDao productDao = new ProductDaoImpl(); @Test public void save() { Product product = productDao.loadById(18L); product.setId(null); product.setProductName("yhptest......"); productDao.save(product); } @Test public void remove() { Product product = productDao.loadById(19L); System.out.println(product); productDao.remove(19L); product = productDao.loadById(19L); System.out.println(product); } @Test public void update() { Product product = productDao.loadById(22L); System.out.println(product); product.setProductName("yhptest......edit"); productDao.update(product); product = productDao.loadById(22L); System.out.println(product); } @Test public void loadById() { //obj.sout System.out.println(productDao.loadById(1L)); } @Test public void loadAll() { for (Product product : productDao.loadAll()) { System.out.println(product); } } }
4.5.注意
配置XML中的约束,使其有提示:
5.Mybatis工具类
5.1.MybatisUtil抽取
5.1.1.为什么要抽取
- 其实每个Dao的方法都要获取SQLSession,并且使用完都要关闭,对于像获取和关闭等操作都应该交给工具处理;
5.1.2.抽取理论分析
SqlSessionFactoryBuilder:
建造者模式:我们最后拿到的这个对象是非常复杂的. 用这个建造者就它先为我们把这些复杂的代码完成。这个类可以被实例化,使用和丢弃。一旦你创建了SqlSessionFactory后,这个类对象就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例,但是最好的方式是不需要保持它一直存在来保证所有XML解析资源,因为还有更重要的事情要做;
SqlSessionFactory:
一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。没有理由来处理或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。这样的操作将被视为是非常糟糕的。因此SqlSessionFactory的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。然而这两种方法都不认为是最佳实践。这样的话,你可以考虑依赖注入容器,比如Google Guice或Spring。这样的框架允许你创建支持程序来管理单例SqlSessionFactory的生命周期;
SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet架构中的HttpSession。如果你现在正用任意的Web框架,要考虑SqlSession放在一个和HTTP请求对象相似的范围内。换句话说,基于收到的HTTP请求,你可以打开了一个SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要;
5.1.3.抽取
5.2.使用工具完成CRUD
5.2.1.查询一条数据
sql
代码
5.2.2.查询所有数据
sql
代码
5.2.3.添加一条数据
注意:添加的时候一定要记住提交事务(配置事务、表结构支持事务)
sql
代码
5.2.4.修改一条数据
sql
代码
5.2.5.删除一条数据
sql
代码
6.SQL映射器Mapper
6.1.引入
引入:之前通过Mybatis操作数据库的时候,除了写接口,还要写实现类。MyBatis基于动态代理机制,让我们无需再编写Dao的实现,但是必须要遵循一定的规范:
传统Dao接口,现在名称统一以Mapper结尾:例如:IUserDao --> UserMapper
还有我们映射器配置文件要和映射器在同一个包:
(1)包:cn.itsource.mapper中(UserMapper接口 和 UserMapper.xml)
UserMapper.xml中namespace直接写UserMapper接口的的完全限定名;
映射文件:
<mapper namespace="cn.itsource.mybatis.mapper.UserMapper"> <select id="接口的方法名" parameterType="long" resultType="User"> Select * from t_user where id = #{id} </select> </mapper>
6.2.映射器实现步骤
根据需求,创建模型相关的Mapper接口,例如:UserMapper;
在同包下编写映射文件,例如:UserMapper.xml;
(1)Mapper映射文件的命名空间,必须和接口的"完全限定名"一致;
(2)定义sql标签的id,需要和"接口的方法名"一致;
- 在Mybatis核心配置文件中配置(或注册)Mapper映射文件;
- 测试;
友情提示:最好不要在mapper接口中使用方法重载,因为sql标签的id即为方法名,写重载方法容易出问题;
6.3.实现
接口实现方式一(传统):
接口实现方式二(映射器):
6.4.添加是返回自增长的ID
一般来说数据库表都有一个主键id,而且是自增长的。在添加数据时,如果不添加id,那么数据库会自动获取当前最大id,将这个 最大id自增1个之后作为即将要添加数据的id值;
有的时候我们在执行insert提交之后,需要获取这个自增id。因为有可能会作为下一次查询的依据,或者下一个插入的外键的凭证;
6.4.1.方式一:
XxxMapper写法: public interface ProductMapper { //自增长ID void insert1(Product product); } XxxMapper.xml写法: <!-- 插入数据并返回自增ID 有自增ID功能数据库可以采用useGeneratedKeys="true"开启判断是否是自增ID keyProperty="id" 指定插入数据后自增ID返回时赋值给实体类的那个属性(这里是id属性) --> <!-- void insert1(Product product) --> <insert id="insert1" useGeneratedKeys="true" keyProperty="id"> insert into product(productName) values(#{productName}) </insert> 测试: @Test public void testInsert(){ SqlSession session = MybatisUtil.getSqlSession(); ProductMapper mapper = session.getMapper(ProductMapper.class); Product product = new Product(); product.setProductName("绿茶111"); System.out.println("====执行前===="+product.getId()); mapper.insert1(product); System.out.println("====执行后===="+product.getId()); session.commit(); session.close(); }
javaweb实训第六天下午——Mybatis基础(3)https://developer.aliyun.com/article/new/database?spm=a2c6h.12873639.article-detail.4.2cd86ab7dyZ9bx&publish=1415631#/