初级版本的高级查询实现是没有问题的。然而,存在着一些你不尽人意的地方
问题1:拼接SQL依然麻烦,不爽!
问题2:使用了where1=1,降低性能
问题3:从责任分离上考虑,DAO是不应该做SQL拼接的,DAO是负责做CRUD的因为查询对象拥有查询信息,应该把拼接SQL的重任交给他。
1 解决责任分离的问题:
把查询SQL和参数封装到Query对象
public class ProductQueryObject {
/**
* 拼接SQL
* @return 拼接好查询条件的SQL
*
* 此时ProducctQueryObject:
* 既封装有查询的SQL:querySql属性
* 也封装了查询的条件:productName,minSalePrice,maxSalePrice属性
* --------------------------------
* 可以把ProductQueryObject作为参数,传递给MyBatis.
*/
public String getQuerySql() {
//拼接SQL
StringBuilder sql = new StringBuilder(" WHERE 1=1 ");
//若输入了商品名称
if (StringUtil.hasLength(productName)) {//名字占位符
sql.append(" AND productName LIKE CONCAT('%',#{productName},'%')");
}
//最低零售价
if (minSalePrice != null) {
sql.append(" AND salePrice >= #{minSalePrice}");
}
//最高零售价
if (maxSalePrice != null) {
sql.append(" AND salePrice <= #{maxSalePrice}");
}
System.out.println("sql="+sql);
return sql.toString();
}
private String productName;//商品名称
private BigDecimal minSalePrice;//最低商品零售价
private BigDecimal maxSalePrice;//最高商品零售价
public String getProductName() {
return productName;
}
public BigDecimal getMinSalePrice() {
return minSalePrice;
}
public BigDecimal getMaxSalePrice() {
return maxSalePrice;
}
public void setProductName(String productName) {
this.productName = productName;
}
public void setMinSalePrice(BigDecimal minSalePrice) {
this.minSalePrice = minSalePrice;
}
public void setMaxSalePrice(BigDecimal maxSalePrice) {
this.maxSalePrice = maxSalePrice;
}
}
XML映射文件
其中${querySql}是ProductQueryObject对象中的get方法
这里表示:获取ProductQueryObject的querySql属性值,并设置到SQL中:
此时SQL: SELECT * FROM product WHERE 1=1 …….#{productName}…..#{minSale}…..
<mapper namespace="cn.itsource.shopping.mapper.ProductMapper">
<select id="list" resultType="Product">
SELECT * FROM product
select>
<select id="advanceQuery" parameterType="cn.itsource.shopping.query.ProductQueryObject" resultType="Product">
SELECT * FROM product ${querySql}
select>
mapper>
2 解决 WHERE1=1 的问题
public class ProductQueryObject {
//封装查询条件如:productName = LIKE XX
private List conditions = new ArrayList<>();
//解决 where1=1 的问题
//拼接查询条件的SQL
public String getQuerySql() {
//拼接SQL
StringBuilder sql = new StringBuilder();
//若输入了商品名称
if (StringUtil.hasLength(productName)) {//名字占位符
conditions.add(" productName LIKE CONCAT('%',#{productName},'%')");
}
//最低零售价
if (minSalePrice != null) {
conditions.add(" salePrice >= #{minSalePrice}");
}
//最高零售价
if (maxSalePrice != null) {
conditions.add(" salePrice <= #{maxSalePrice}");
}
for (int i = 0; i < conditions.size(); i++) {
if(i==0){
sql.append(" WHERE ");
}else{
sql.append(" AND ");
}
sql.append(conditions.get(i));
}
System.out.println("sql="+sql);
return sql.toString();
}
private String productName;//商品名称
private BigDecimal minSalePrice;//最低商品零售价
private BigDecimal maxSalePrice;//最高商品零售价
public String getProductName() {
return productName;
}
public BigDecimal getMinSalePrice() {
return minSalePrice;
}
public BigDecimal getMaxSalePrice() {
return maxSalePrice;
}
public void setProductName(String productName) {
this.productName = productName;
}
public void setMinSalePrice(BigDecimal minSalePrice) {
this.minSalePrice = minSalePrice;
}
public void setMaxSalePrice(BigDecimal maxSalePrice) {
this.maxSalePrice = maxSalePrice;
}
}
XML映射文件
跟上面的一样不需要改变!
<mapper namespace="cn.itsource.shopping.mapper.ProductMapper">
<select id="list" resultType="Product">
SELECT * FROM product
select>
<select id="advanceQuery" parameterType="cn.itsource.shopping.query.ProductQueryObject" resultType="Product">
SELECT * FROM product ${querySql}
select>
mapper>
实现类代码
public class ProductDAOImpl implements IProductDAO {
public List list() {
SqlSession session = MyBatisUtil.INSTANCE.openSession();
try {
return session.selectList("cn.itsource.shopping.mapper.ProductMapper.list");
} finally {
session.close();
}
}
public List query(ProductQueryObject qo) {
SqlSession session = MyBatisUtil.INSTANCE .openSession();
try {
return session.selectList("cn.itsource.shopping.mapper.ProductMapper.advanceQuery", qo);
} finally {
session.close();
}
}
}
实现接口代码
public interface IProductDAO {
List list();
//高级查询的方法
List query (ProductQueryObject qo);
}
测试类代码
public class ProductDAOTest {
private IProductDAO dao = new ProductDAOImpl();
@Test
public void testList() {
List list = dao.list();
for (Product p : list) {
System.out.println(p);
}
}
@Test
public void testQuery() {
ProductQueryObject qo = new ProductQueryObject();
qo.setProductName("iphone8s");
qo.setMinSalePrice(new BigDecimal("6000"));
qo.setMaxSalePrice(new BigDecimal("9000"));
//------------------------------------
List list = dao.query(qo);
for (Product p : list) {
System.out.println(p);
}
}
}
Util工具类
public enum MyBatisUtil {
INSTANCE;
private static SqlSessionFactory sessionFactory = null;
static {
try {
sessionFactory = new SqlSessionFactoryBuilder().build(Resources
.getResourceAsStream("MyBatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public SqlSession openSession() {
return sessionFactory.openSession();
}
}
public class StringUtil {
public static boolean hasLength(String str) {
return str != null && !"".equals(str.trim());
}
}
商品对象类
public class Product {
private Long id;
private String productName;
private String brand;
private String supplier;
private BigDecimal salePrice;
private BigDecimal costPrice;
private Double cutoff;
private Long dir_id;//分类编号
public Long getId() {
return id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getBrand() {
return brand;
}
public String getSupplier() {
return supplier;
}
public BigDecimal getSalePrice() {
return salePrice;
}
public BigDecimal getCostPrice() {
return costPrice;
}
public Double getCutoff() {
return cutoff;
}
public Long getDir_id() {
return dir_id;
}
public void setId(Long id) {
this.id = id;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setSupplier(String supplier) {
this.supplier = supplier;
}
public void setSalePrice(BigDecimal salePrice) {
this.salePrice = salePrice;
}
public void setCostPrice(BigDecimal costPrice) {
this.costPrice = costPrice;
}
public void setCutoff(Double cutoff) {
this.cutoff = cutoff;
}
public void setDir_id(Long dir_id) {
this.dir_id = dir_id;
}
public String toString() {
return "Product [id=" + id + ", productName=" + productName + ", brand=" + brand + ", suppliet=" + supplier
+ ", salePrice=" + salePrice + ", costPrice=" + costPrice + ", cutoff=" + cutoff + ", dir_id=" + dir_id
+ "]";
}
}
MyBatis的映射文件
<configuration>
<properties resource="db.properties" />
<typeAliases>
<typeAlias type="cn.itsource.shopping.domain.Product" alias="Product" />
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${usename}" />
<property name="password" value="${password}" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="cn\itsource\shopping\domain\ProductMapper.xml" />
mappers>
configuration>
db.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo?useSSL=false
usename=root
password=111111
日志文件
其中第二行是日志跟踪哪一包具体到哪一个类的错误信息!
log4j.rootLogger=ERROR, stdout
log4j.logger.cn.itsource.shopping=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n