MyBatis之Mapper封装,Oracle自增长主键的实现
功能:实现Mapper接口,封装SqlSession之类的调用,进一步简化程序的调用,就像操作普通对象一样,感觉不到后台数据库
预备:请先阅读MyBatis之工作原理,简单实体的增加、修改、删除、查询
一、目录结构
com.clzhang.mybatis.entity ProductBean.java MyBatis的entity类 com.clzhang.mybatis.mapper MyBatisSessionFactory.java SqlSessionFactory获取类 com.clzhang.mybatis.mapper ProductMapper.java MyBatis的mapper处理类 com.clzhang.mybatis.mapper.impl ProductMapperImpl.java ProductMapper的接口实现类 com.clzhang.mybatis MyBatisTest3.java 测试类,最终应该是在service的package中调用mapper中的方法。 resources\config mybatis-config.xml MyBatis的配置文件 resources\com\clzhang\mybatis\mapper ProductMapper.xml MyBatis的mapper配置文件
二、假定数据库已经创建,表结构也已经创建,并且有测试数据
CREATE TABLE PRODUCT( PRODID NUMBER(38) NOT NULL PRIMARY KEY, PRODSERIAL VARCHAR2(20), PRODNAME VARCHAR2(50) NOT NULL, CATEGORYNAME VARCHAR2(20), PRODSPEC VARCHAR2(50), PRODPRICE NUMBER(12,2), PRODDESC VARCHAR2(1024), PRODIMAGE VARCHAR2(150), ISNEW NUMBER(38) NOT NULL, ISRECOMMEND NUMBER(38) NOT NULL, ISSHOW NUMBER(38) NOT NULL, USERNAME VARCHAR2(20) NOT NULL, HANDLETIME DATE, PRODTHUMBNAIL VARCHAR2(150)); CREATE SEQUENCE SEQ_PRODUCT;
三、具体步骤
1. 创建entity类
package com.clzhang.mybatis.entity; import java.sql.Timestamp; public class ProductBean { private int prodId; private String prodSerial; private String prodName; private String categoryname; private String prodSpec; private double prodPrice; private String prodDesc; private String prodImage; private int isNew; private int isRecommend; private int isShow; private String username; private Timestamp handletime; private String prodThumbnail; public int getProdId() { return prodId; } public void setProdId(int prodId) { this.prodId = prodId; } public String getProdSerial() { return prodSerial; } public void setProdSerial(String prodSerial) { this.prodSerial = prodSerial; } public String getProdName() { return prodName; } public void setProdName(String prodName) { this.prodName = prodName; } public String getCategoryname() { return categoryname; } public void setCategoryname(String categoryname) { this.categoryname = categoryname; } public String getProdSpec() { return prodSpec; } public void setProdSpec(String prodSpec) { this.prodSpec = prodSpec; } public double getProdPrice() { return prodPrice; } public void setProdPrice(double prodPrice) { this.prodPrice = prodPrice; } public String getProdDesc() { return prodDesc; } public void setProdDesc(String prodDesc) { this.prodDesc = prodDesc; } public String getProdImage() { return prodImage; } public void setProdImage(String prodImage) { this.prodImage = prodImage; } public int getIsNew() { return isNew; } public void setIsNew(int isNew) { this.isNew = isNew; } public int getIsRecommend() { return isRecommend; } public void setIsRecommend(int isRecommend) { this.isRecommend = isRecommend; } public int getIsShow() { return isShow; } public void setIsShow(int isShow) { this.isShow = isShow; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Timestamp getHandletime() { return handletime; } public void setHandletime(Timestamp handletime) { this.handletime = handletime; } public String getProdThumbnail() { return prodThumbnail; } public void setProdThumbnail(String prodThumbnail) { this.prodThumbnail = prodThumbnail; } }
2. 创建Mapper接口类
package com.clzhang.mybatis.mapper; import java.util.*; import com.clzhang.mybatis.entity.ProductBean; public interface ProductMapper { public void insertProduct(ProductBean product); public void updateProduct(ProductBean product); public void deleteProduct(int prodId); public ProductBean getProductById(int prodId); public List<ProductBean> getProdByCategory(String categoryName); }
3. 创建MyBatisSessionFactory类
package com.clzhang.mybatis.mapper; import java.io.*; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /** * SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。 * 所以定义一个通用类,所以获取SqlSessionFactory句柄的程序都从这儿获取。 * @author acer * */ public class MyBatisSessionFactory { private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml"; private static SqlSessionFactory sqlSessionFactory = null; static { try { InputStream inputStream = Resources.getResourceAsStream(MYBATIS_CONFIG_FILENAME); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { throw new RuntimeException("Get resource error:"+MYBATIS_CONFIG_FILENAME, e); } } public static SqlSessionFactory getSqlSessionFactory(){ return sqlSessionFactory; } }
4. 创建Mapper接口实现类
package com.clzhang.mybatis.mapper.impl; import java.util.*; import org.apache.ibatis.session.SqlSession; import com.clzhang.mybatis.mapper.MemberUserMapper; import com.clzhang.mybatis.mapper.MyBatisSessionFactory; import com.clzhang.mybatis.mapper.ProductMapper; import com.clzhang.mybatis.entity.ProductBean; public class ProductMapperImpl implements ProductMapper { @Override public void insertProduct(ProductBean product) { SqlSession session = MyBatisSessionFactory.getSqlSessionFactory().openSession(); try { // 如果ProductMapper.xml中定义namespace为长文件名,则用传统方式调用 // 以下的updateProduct/deleteProduct,以此类推 // ProductMapper mapper = session.getMapper(ProductMapper.class); // mapper.insertProduct(product); // 如果ProductMapper.xml中定义namespace为短文件名,则可以用如下方式调用 session.insert("ProductMapper.insertProduct", product); session.commit(); } finally { session.close(); } } @Override public void updateProduct(ProductBean product) { SqlSession session = MyBatisSessionFactory.getSqlSessionFactory().openSession(); try { session.update("ProductMapper.updateProduct", product); session.commit(); } finally { session.close(); } } @Override public void deleteProduct(int prodId) { SqlSession session = MyBatisSessionFactory.getSqlSessionFactory().openSession(); try { session.delete("ProductMapper.deleteProduct", prodId); session.commit(); } finally { session.close(); } } @Override public ProductBean getProductById(int prodId) { SqlSession session = MyBatisSessionFactory.getSqlSessionFactory().openSession(); ProductBean product = null; try { product = (ProductBean) session.selectOne("ProductMapper.getProductById", prodId); } finally { session.close(); } return product; } @Override public List<ProductBean> getProdByCategory(String categoryName) { Map<String, Object> params = new HashMap<String, Object>(); params.put("categoryName", categoryName); SqlSession session = MyBatisSessionFactory.getSqlSessionFactory().openSession(); List<ProductBean> list = null; try { list = session.selectList("ProductMapper.getProdByCategory", params); } finally { session.close(); } return list; } }
5. 修改mybatis-config.xml配置文件,增加Product实体与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> <settings> <setting name="cacheEnabled" value="false" /> <setting name="useGeneratedKeys" value="true" /> <setting name="defaultExecutorType" value="REUSE" /> </settings> <typeAliases> <typeAlias alias="Product" type="com.clzhang.mybatis.entity.ProductBean"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="mytest"/> <property name="password" value="test001"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/clzhang/mybatis/mapper/ProductMapper.xml" /> </mappers> </configuration>
6. 创建ProductMapper.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"> <!-- 1.namespace的值可以设置得非常短比如:ProductMapper,如果项目不大的情况下,可以考虑这样使用。 好处是在Java代码如下调用即可:session.insert("ProductMapper.insertProduct", product); 2.如果项目非常大的话(或者是与Spring整合),那么还是建议使用长文件名做标识。 --> <mapper namespace="ProductMapper"> <!-- 默认情况下是没有开启缓存的,下条代码是开启二级缓存的,作用如下: 1.•映射语句文件中的所有 select 语句将会被缓存。 2.•映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。 3.•缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。 ...... --> <cache /> <!-- 用来定义可重用的SQL代码段 --> <sql id="selectProdSQL"> PRODID,PRODSERIAL,PRODNAME,CATEGORYNAME,PRODSPEC,PRODPRICE,PRODDESC,PRODIMAGE,ISNEW,ISRECOMMEND,ISSHOW,USERNAME,HANDLETIME,PRODTHUMBNAIL </sql> <!--以单个对象方式返回--> <select id="getProductById" resultType="Product" parameterType="int"> select <include refid="selectProdSQL"/> FROM PRODUCT WHERE PRODID = #{prodId} </select> <resultMap type="Product" id="prodByCategoryMap"> <id property="prodId" column="prodId"/> <!--有需要做数据库到实体类名称转换的,可以写在这里--> <!-- <result property="objname" column="dbname"/> --> </resultMap> <!--以List方式返回多个结果--> <select id="getProdByCategory" resultMap="prodByCategoryMap" parameterType="string"> select <include refid="selectProdSQL"/> FROM PRODUCT WHERE CATEGORYNAME = #{categoryName} </select> <!--Oracle的实现自增长主键的方式--> <!--对于数据库中允许为空的字段,需要在这里指定字段类型,因为MyBatis不知道你传入的 null 参数对应的 jdbc 类型是什么;如果没有指定,则需要在插入数据时全部字段都要设置值,哪怕是空值!--> <insert id="insertProduct" parameterType="Product"> <selectKey keyProperty="prodId" resultType="int" order="BEFORE"> select SEQ_PRODUCT.nextval from DUAL </selectKey> INSERT INTO PRODUCT (PRODID,PRODSERIAL,PRODNAME,CATEGORYNAME,PRODSPEC,PRODPRICE,PRODDESC,PRODIMAGE,ISNEW,ISRECOMMEND,ISSHOW,USERNAME,HANDLETIME,PRODTHUMBNAIL) VALUES(#{prodId}, #{prodSerial,jdbcType=VARCHAR}, #{prodName}, #{categoryname,jdbcType=VARCHAR}, #{prodSpec,jdbcType=VARCHAR}, #{prodPrice,jdbcType=DOUBLE}, #{prodDesc,jdbcType=VARCHAR}, #{prodImage,jdbcType=VARCHAR}, #{isNew}, #{isRecommend}, #{isShow}, #{username}, #{handletime,jdbcType=DATE}, #{prodThumbnail,jdbcType=VARCHAR}) </insert> <update id="updateProduct" parameterType="Product"> update PRODUCT set PRODSERIAL = #{prodSerial,jdbcType=VARCHAR}, PRODNAME = #{prodName}, CATEGORYNAME = #{categoryname,jdbcType=VARCHAR}, PRODSPEC = #{prodSpec,jdbcType=VARCHAR}, PRODPRICE = #{prodPrice,jdbcType=DOUBLE}, PRODDESC = #{prodDesc,jdbcType=VARCHAR}, PRODIMAGE = #{prodImage,jdbcType=VARCHAR}, ISNEW = #{isNew}, ISRECOMMEND = #{isRecommend}, ISSHOW = #{isShow}, USERNAME = #{username}, HANDLETIME = #{handletime,jdbcType=DATE}, PRODTHUMBNAIL = #{prodThumbnail,jdbcType=VARCHAR} where PRODID = #{prodId} </update> <delete id="deleteProduct" parameterType="int"> delete from PRODUCT where PRODID = #{prodId} </delete> </mapper>
7. 创建测试类,到了这里,代码就变得非常简单了
package com.clzhang.mybatis; import java.util.List; import org.junit.Test; import com.clzhang.mybatis.entity.ProductBean; import com.clzhang.mybatis.mapper.ProductMapper; import com.clzhang.mybatis.mapper.impl.ProductMapperImpl; /** * 因为由ProductMapperImpl之类的数据库实现类实现了详细的数据库提交接口; * 所以此处的代码非常简单,就是Java对象的操作而已。 */ public class MyBatisTest3 { private ProductMapper productMapper = new ProductMapperImpl(); // @Test public void testInsert() { ProductBean entity = new ProductBean(); // 注意:因ProductMapper.xml中已经设置了字段空值时如果处理,所以此处不一定要设置实体的所有属性。 entity.setProdSerial("BT072-8(K8)"); entity.setProdName("相册"); entity.setCategoryname("套件"); entity.setProdSpec("230*200 240*220cm"); entity.setProdPrice(12.0); entity.setProdDesc("面料:粘丝与棉交织......"); entity.setProdImage("/upload/product/201211260815461.jpg"); entity.setIsNew(0); entity.setIsRecommend(0); entity.setIsShow(0); entity.setUsername("admin"); entity.setHandletime(new java.sql.Timestamp(new java.util.Date().getTime())); entity.setProdThumbnail("/upload/product/20121126081626394.jpg"); productMapper.insertProduct(entity); System.out.println("新加的实体主键:" + entity.getProdId()); } // @Test public void testUpdate() { int pridId = 3; ProductBean entity = productMapper.getProductById(pridId); entity.setProdName("新产品"); productMapper.updateProduct(entity); } // @Test public void testDelete() { int prodId = 2; productMapper.deleteProduct(prodId); } // @Test public void getProductById() { int pridId = 3; ProductBean entity = productMapper.getProductById(pridId); if(entity != null){ System.out.println(entity.getProdName()); } else{ System.out.println("prodId不存在!" + pridId); } } // @Test public void getProdByCategoryName() { List<ProductBean> list = productMapper.getProdByCategory("套件"); for(ProductBean entity: list) { System.out.println(entity.getProdName()); } } }
四、单独测试各个模块
解除注释JUnit各单元,然后键盘输入:alt+shift+X,T,分别进行测试。